ngb-datepicker 在 angular material 输入(matInput)中不工作
ngb-datepicker not working in angular material input(matInput)
我想在 material Input 中使用 ngb-datepicker。我成功地将日期选择器应用于垫输入。但是月份和年份下拉菜单存在问题。
我尝试了以下片段:
<mat-form-field>
<input matInput placeholder="Select Valid Till" name="GodownValidTill" [(ngModel)]="GodownValidTill" ngbDatepicker #d2="ngbDatepicker" required readonly>
<mat-icon style="float:right;height:20px;width:20px;" (click)="d2.toggle()" svgIcon="calendar" title="Calendar"></mat-icon>
</mat-form-field>
有没有完美工作的解决方案?
我不确定到底是什么问题,但是将两个库集成在一起没有问题。我使用了与您几乎完全相同的代码。
<mat-form-field class="example-full-width">
<input matInput placeholder="Favorite food" name="GodownValidTill" [(ngModel)]="GodownValidTill" (ngModelChange)="onSelect($event)" ngbDatepicker #d="ngbDatepicker" required readonly>
<mat-icon (click)="d.toggle()">calendar-today</mat-icon>
</mat-form-field>
功能方面,没有问题。但当然,您需要对 CSS/styling 进行自己的更改。我已经在 here.
上复制了一个演示
为什么不同时使用这两个库,为什么不只使用 Angular Boostrap 或 Angular Material?这样,您就不需要管理不同的包。这两个库都有自己的 Datepicker 组件 (Material Datepicker/Ngbootstrap Datepicker)。
我尝试重现该问题,发现默认情况下 ngbDatePicker 附加在它所附加的输入字段下方。当我们使用 matInput 时,实际的输入字段会被各种 material 类 包围,这会导致日期选择器出现问题。
所以,我们可以做的是,我们可以像这样使用 container
属性 或 ngbDatepicker 将日期选择器附加到正文。容器 属性 目前仅支持 "body" 作为值。
<mat-form-field>
<input matInput type="text" ngbDatepicker container="body" #d="ngbDatepicker" (click)="d.open()" placeholder="Date Picker with issue"/>
</mat-form-field>
这是相同的 stackblitz demo。我希望这会有所帮助。
另一种方法是格式化 material 日期选择器。查看 final result
第一步是创建自定义 Header、
<div class="mat-calendar-header">
<div class="mat-calendar-controls">
<button mat-icon-button type="button" class="mat-calendar-previous-button arrow"
[disabled]="!previousEnabled()" (click)="customPrev()"
[attr.aria-label]="prevButtonLabel">
</button>
<select [ngModel]="dateMonth" (ngModelChange)="dateMonth=$event;select()"class="custom-select">
<option *ngFor="let month of months;let i=index" [value]="i">{{month}}</option>
</select>
<select [ngModel]="dateYear" (ngModelChange)="dateYear=+$event;select()" class="custom-select" style="width:70%" >
<option *ngFor="let i of [-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10]" [value]="dateYear+i">{{dateYear+i}}</option>
</select>
<button mat-icon-button type="button" class="mat-calendar-next-button arrow"
[disabled]="!nextEnabled()" (click)="customNext()"
[attr.aria-label]="nextButtonLabel">
</button>
</div>
</div>
带个.css 看一下类似ngb-datepicker
.custom-select {
display: inline-block;
width: 100%;
height: calc(1.5em + .75rem + 2px);
padding: .375rem 1.75rem .375rem .75rem;
font-size: .8rem;
font-weight: 200;
line-height: 1.5;
color: #495057;
vertical-align: middle;
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") right .75rem center/8px 10px no-repeat #fff;
border: 1px solid #ced4da;
border-radius: .25rem;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.arrow{
margin-top: -.25rem;
}
如果我们的 header 扩展了 MatCalendarHeader,我们可以实现 OnInit - 将值放入 Year 和 Month 的 combo-box,并添加 ElementRef y Renderer2。我使用 Renderer2 来 add/remove class removeRow
.removeRow tbody tr:first-child td{
display:none
}
这允许我们在每月第一天的日期是星期日、星期一或星期四时不显示第一行 - 在 material-date-picker 中它显示月份,但我们在combo-box.
export class ExampleHeader extends MatCalendarHeader<any> implements OnInit {
calendar:any
months=[
"January","February","March","April","May","June","July","August","September","October","November","December"]
dateYear:any
dateMonth:any
constructor(_intl:MatDatepickerIntl,
_calendar: MatCalendar<any>, _dateAdapter: DateAdapter<any>,
@Inject(MAT_DATE_FORMATS) _dateFormats: MatDateFormats, cdr: ChangeDetectorRef,private el:ElementRef,private render:Renderer2){
super(_intl,_calendar,_dateAdapter,_dateFormats,cdr)
this.calendar=_calendar;
this.dateYear=this.calendar.activeDate?this.calendar.activeDate.getFullYear():new Date().getFullYear()
this.dateMonth=this.calendar.activeDate?this.calendar.activeDate.getMonth():new Date().getMonth()
}
select()
{
this.calendar.activeDate=new Date(this.dateYear,this.dateMonth)
this.refreshCombo(this.dateMonth,this.dateYear)
}
ngOnInit()
{
this.refreshCombo(this.calendar.activeDate.getMonth(),this.calendar.activeDate.getFullYear())
}
refreshCombo(month,year)
{
this.dateMonth=month;
this.dateYear=year;
const element=this.el.nativeElement.parentElement
if (new Date(year,month,1).getDay()<=2)
this.render.addClass(element,'removeRow')
else
this.render.removeClass(element,'removeRow')
}
/** Handles user clicks on the previous button. */
customPrev(): void {
this.previousClicked()
this.refreshCombo(this.calendar.activeDate.getMonth(),this.calendar.activeDate.getFullYear());
}
/** Handles user clicks on the next button. */
customNext(): void {
this.nextClicked()
this.refreshCombo(this.calendar.activeDate.getMonth(),this.calendar.activeDate.getFullYear());
}
我想在 material Input 中使用 ngb-datepicker。我成功地将日期选择器应用于垫输入。但是月份和年份下拉菜单存在问题。
我尝试了以下片段:
<mat-form-field>
<input matInput placeholder="Select Valid Till" name="GodownValidTill" [(ngModel)]="GodownValidTill" ngbDatepicker #d2="ngbDatepicker" required readonly>
<mat-icon style="float:right;height:20px;width:20px;" (click)="d2.toggle()" svgIcon="calendar" title="Calendar"></mat-icon>
</mat-form-field>
有没有完美工作的解决方案?
我不确定到底是什么问题,但是将两个库集成在一起没有问题。我使用了与您几乎完全相同的代码。
<mat-form-field class="example-full-width">
<input matInput placeholder="Favorite food" name="GodownValidTill" [(ngModel)]="GodownValidTill" (ngModelChange)="onSelect($event)" ngbDatepicker #d="ngbDatepicker" required readonly>
<mat-icon (click)="d.toggle()">calendar-today</mat-icon>
</mat-form-field>
功能方面,没有问题。但当然,您需要对 CSS/styling 进行自己的更改。我已经在 here.
上复制了一个演示为什么不同时使用这两个库,为什么不只使用 Angular Boostrap 或 Angular Material?这样,您就不需要管理不同的包。这两个库都有自己的 Datepicker 组件 (Material Datepicker/Ngbootstrap Datepicker)。
我尝试重现该问题,发现默认情况下 ngbDatePicker 附加在它所附加的输入字段下方。当我们使用 matInput 时,实际的输入字段会被各种 material 类 包围,这会导致日期选择器出现问题。
所以,我们可以做的是,我们可以像这样使用 container
属性 或 ngbDatepicker 将日期选择器附加到正文。容器 属性 目前仅支持 "body" 作为值。
<mat-form-field>
<input matInput type="text" ngbDatepicker container="body" #d="ngbDatepicker" (click)="d.open()" placeholder="Date Picker with issue"/>
</mat-form-field>
这是相同的 stackblitz demo。我希望这会有所帮助。
另一种方法是格式化 material 日期选择器。查看 final result
第一步是创建自定义 Header、
<div class="mat-calendar-header">
<div class="mat-calendar-controls">
<button mat-icon-button type="button" class="mat-calendar-previous-button arrow"
[disabled]="!previousEnabled()" (click)="customPrev()"
[attr.aria-label]="prevButtonLabel">
</button>
<select [ngModel]="dateMonth" (ngModelChange)="dateMonth=$event;select()"class="custom-select">
<option *ngFor="let month of months;let i=index" [value]="i">{{month}}</option>
</select>
<select [ngModel]="dateYear" (ngModelChange)="dateYear=+$event;select()" class="custom-select" style="width:70%" >
<option *ngFor="let i of [-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10]" [value]="dateYear+i">{{dateYear+i}}</option>
</select>
<button mat-icon-button type="button" class="mat-calendar-next-button arrow"
[disabled]="!nextEnabled()" (click)="customNext()"
[attr.aria-label]="nextButtonLabel">
</button>
</div>
</div>
带个.css 看一下类似ngb-datepicker
.custom-select {
display: inline-block;
width: 100%;
height: calc(1.5em + .75rem + 2px);
padding: .375rem 1.75rem .375rem .75rem;
font-size: .8rem;
font-weight: 200;
line-height: 1.5;
color: #495057;
vertical-align: middle;
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") right .75rem center/8px 10px no-repeat #fff;
border: 1px solid #ced4da;
border-radius: .25rem;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.arrow{
margin-top: -.25rem;
}
如果我们的 header 扩展了 MatCalendarHeader,我们可以实现 OnInit - 将值放入 Year 和 Month 的 combo-box,并添加 ElementRef y Renderer2。我使用 Renderer2 来 add/remove class removeRow
.removeRow tbody tr:first-child td{
display:none
}
这允许我们在每月第一天的日期是星期日、星期一或星期四时不显示第一行 - 在 material-date-picker 中它显示月份,但我们在combo-box.
export class ExampleHeader extends MatCalendarHeader<any> implements OnInit {
calendar:any
months=[
"January","February","March","April","May","June","July","August","September","October","November","December"]
dateYear:any
dateMonth:any
constructor(_intl:MatDatepickerIntl,
_calendar: MatCalendar<any>, _dateAdapter: DateAdapter<any>,
@Inject(MAT_DATE_FORMATS) _dateFormats: MatDateFormats, cdr: ChangeDetectorRef,private el:ElementRef,private render:Renderer2){
super(_intl,_calendar,_dateAdapter,_dateFormats,cdr)
this.calendar=_calendar;
this.dateYear=this.calendar.activeDate?this.calendar.activeDate.getFullYear():new Date().getFullYear()
this.dateMonth=this.calendar.activeDate?this.calendar.activeDate.getMonth():new Date().getMonth()
}
select()
{
this.calendar.activeDate=new Date(this.dateYear,this.dateMonth)
this.refreshCombo(this.dateMonth,this.dateYear)
}
ngOnInit()
{
this.refreshCombo(this.calendar.activeDate.getMonth(),this.calendar.activeDate.getFullYear())
}
refreshCombo(month,year)
{
this.dateMonth=month;
this.dateYear=year;
const element=this.el.nativeElement.parentElement
if (new Date(year,month,1).getDay()<=2)
this.render.addClass(element,'removeRow')
else
this.render.removeClass(element,'removeRow')
}
/** Handles user clicks on the previous button. */
customPrev(): void {
this.previousClicked()
this.refreshCombo(this.calendar.activeDate.getMonth(),this.calendar.activeDate.getFullYear());
}
/** Handles user clicks on the next button. */
customNext(): void {
this.nextClicked()
this.refreshCombo(this.calendar.activeDate.getMonth(),this.calendar.activeDate.getFullYear());
}