Angular 5 模型绑定不适用于 ng-bootstrap 日期选择器弹出窗口
Angular 5 model binding not working for ng-bootstrap date picker popup
我正在尝试使用 ng-bootstrap 的日期选择器弹出窗口制作我自己的组件(我不想每次使用日期选择器时都需要所有这些标记)。
日期选择器自己运行良好,但该值未绑定回使用该组件的页面。
这是我的日期选择器 - 从 ng-bootstrap 的示例页面复制:
<div class="input-group">
<input class="form-control" placeholder="yyyy-mm-dd" name="dp" [(ngModel)]="selectedDate" ngbDatepicker #d="ngbDatepicker">
<div class="input-group-append">
<button class="btn btn-outline-secondary" (click)="d.toggle()" type="button">
<img src="img/calendar-icon.svg" style="width: 1.2rem; height: 1rem; cursor: pointer;"/>
</button>
</div>
</div>
<hr/>
<pre>Model: {{ selectedDate | json }}</pre>
我的组件:
import { Component, OnInit } from '@angular/core';
import {NgbDateStruct, NgbDateParserFormatter} from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'reo-datepicker-popup',
templateUrl: './datepicker-popup.component.html',
})
export class DatepickerPopupComponent implements OnInit {
selectedDate; any;
constructor() {}
ngOnInit() {
}
}
组件是这样使用的:
<reo-datepicker-popup [(ngModel)]="selectedDatePopup" ngDefaultControl name="datePicker"></reo-datepicker-popup>
我的页面上还有其他控件 [(ngModel)]
按预期工作。我可以在父页面中为 selectedDatePopup
设置默认值 - 该值将向下传播到日期选择器,但在更改时不会返回到父页面。
我试过 @Input()
而不是 [(ngModel)]
,结果相同。我还验证了每个模块中都导入了 NgbModule
(app 模块中的 ngbModule.forRoot()
),并且 FormsModule
总是在 NgbModule
.
之前导入
Angular 版本 5.2.3
ng-bootstrap 版本 1.02
感谢任何帮助。
您需要在 DatePickerPopupComponent 上实现 ControlValueAccessor。这将允许 angular 表单(模板或反应式)与您的组件进行模型绑定。你的 plnkr 不再工作了。我在 StackBlitz 上创建了一个示例。我必须添加一些额外的代码来翻译 ngbDatePicker 的日期。可能有更好的方法来做到这一点。这应该足以让您朝着正确的方向前进。
组件代码应该是这样的:
import { Component, OnInit, forwardRef, Input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, } from '@angular/forms';
export const DATEPICKER_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DatePickerComponent),
multi: true
};
@Component({
selector: 'app-date-picker',
templateUrl: './date-picker.component.html',
providers: [DATEPICKER_VALUE_ACCESSOR]
})
export class DatePickerComponent implements ControlValueAccessor {
selectedDate: any;
disabled = false;
// Function to call when the date changes.
onChange = (date?: Date) => {};
// Function to call when the date picker is touched
onTouched = () => {};
writeValue(value: Date) {
if (!value) return;
this.selectedDate = {
year: value.getFullYear(),
month: value.getMonth(),
day: value.getDate()
}
}
registerOnChange(fn: (date: Date) => void): void {
this.onChange = fn;
}
// Allows Angular to register a function to call when the input has been touched.
// Save the function as a property to call later here.
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}
// Allows Angular to disable the input.
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
// Write change back to parent
onDateChange(value: Date) {
this.onChange(value);
}
// Write change back to parent
onDateSelect(value: any) {
this.onChange(new Date(value.year, value.month - 1, value.day));
}
}
标记:
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input class="form-control"
placeholder="yyyy-mm-dd"
name="dp"
[(ngModel)]="selectedDate"
ngbDatepicker #d="ngbDatepicker"
(change)="onDateChange($event.target.value)"
(dateSelect)="onDateSelect($event)">
<div class="input-group-append">
<button class="btn btn-outline-secondary" (click)="d.toggle()" type="button">
[[]]
</button>
</div>
</div>
</div>
</form>
<hr/>
<pre>Model on date picker: {{ selectedDate | json }}</pre>
组件上的实现:
import { Component, Input } from '@angular/core';
@Component({
selector: 'hello',
template: `<h1>Hello {{name}}!</h1>
<div>
This is the date picker: <app-date-picker [(ngModel)]="selectedDate"></app-date-picker>
</div>
<div>
Model on parent: {{ selectedDate | date:'short' }}
</div>
`,
styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent {
@Input() name: string;
public selectedDate: Date;
constructor() {
this.selectedDate = new Date(2018, 1, 1);
}
}
我正在尝试使用 ng-bootstrap 的日期选择器弹出窗口制作我自己的组件(我不想每次使用日期选择器时都需要所有这些标记)。
日期选择器自己运行良好,但该值未绑定回使用该组件的页面。
这是我的日期选择器 - 从 ng-bootstrap 的示例页面复制:
<div class="input-group">
<input class="form-control" placeholder="yyyy-mm-dd" name="dp" [(ngModel)]="selectedDate" ngbDatepicker #d="ngbDatepicker">
<div class="input-group-append">
<button class="btn btn-outline-secondary" (click)="d.toggle()" type="button">
<img src="img/calendar-icon.svg" style="width: 1.2rem; height: 1rem; cursor: pointer;"/>
</button>
</div>
</div>
<hr/>
<pre>Model: {{ selectedDate | json }}</pre>
我的组件:
import { Component, OnInit } from '@angular/core';
import {NgbDateStruct, NgbDateParserFormatter} from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'reo-datepicker-popup',
templateUrl: './datepicker-popup.component.html',
})
export class DatepickerPopupComponent implements OnInit {
selectedDate; any;
constructor() {}
ngOnInit() {
}
}
组件是这样使用的:
<reo-datepicker-popup [(ngModel)]="selectedDatePopup" ngDefaultControl name="datePicker"></reo-datepicker-popup>
我的页面上还有其他控件 [(ngModel)]
按预期工作。我可以在父页面中为 selectedDatePopup
设置默认值 - 该值将向下传播到日期选择器,但在更改时不会返回到父页面。
我试过 @Input()
而不是 [(ngModel)]
,结果相同。我还验证了每个模块中都导入了 NgbModule
(app 模块中的 ngbModule.forRoot()
),并且 FormsModule
总是在 NgbModule
.
Angular 版本 5.2.3
ng-bootstrap 版本 1.02
感谢任何帮助。
您需要在 DatePickerPopupComponent 上实现 ControlValueAccessor。这将允许 angular 表单(模板或反应式)与您的组件进行模型绑定。你的 plnkr 不再工作了。我在 StackBlitz 上创建了一个示例。我必须添加一些额外的代码来翻译 ngbDatePicker 的日期。可能有更好的方法来做到这一点。这应该足以让您朝着正确的方向前进。
组件代码应该是这样的:
import { Component, OnInit, forwardRef, Input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, } from '@angular/forms';
export const DATEPICKER_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DatePickerComponent),
multi: true
};
@Component({
selector: 'app-date-picker',
templateUrl: './date-picker.component.html',
providers: [DATEPICKER_VALUE_ACCESSOR]
})
export class DatePickerComponent implements ControlValueAccessor {
selectedDate: any;
disabled = false;
// Function to call when the date changes.
onChange = (date?: Date) => {};
// Function to call when the date picker is touched
onTouched = () => {};
writeValue(value: Date) {
if (!value) return;
this.selectedDate = {
year: value.getFullYear(),
month: value.getMonth(),
day: value.getDate()
}
}
registerOnChange(fn: (date: Date) => void): void {
this.onChange = fn;
}
// Allows Angular to register a function to call when the input has been touched.
// Save the function as a property to call later here.
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}
// Allows Angular to disable the input.
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
// Write change back to parent
onDateChange(value: Date) {
this.onChange(value);
}
// Write change back to parent
onDateSelect(value: any) {
this.onChange(new Date(value.year, value.month - 1, value.day));
}
}
标记:
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input class="form-control"
placeholder="yyyy-mm-dd"
name="dp"
[(ngModel)]="selectedDate"
ngbDatepicker #d="ngbDatepicker"
(change)="onDateChange($event.target.value)"
(dateSelect)="onDateSelect($event)">
<div class="input-group-append">
<button class="btn btn-outline-secondary" (click)="d.toggle()" type="button">
[[]]
</button>
</div>
</div>
</div>
</form>
<hr/>
<pre>Model on date picker: {{ selectedDate | json }}</pre>
组件上的实现:
import { Component, Input } from '@angular/core';
@Component({
selector: 'hello',
template: `<h1>Hello {{name}}!</h1>
<div>
This is the date picker: <app-date-picker [(ngModel)]="selectedDate"></app-date-picker>
</div>
<div>
Model on parent: {{ selectedDate | date:'short' }}
</div>
`,
styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent {
@Input() name: string;
public selectedDate: Date;
constructor() {
this.selectedDate = new Date(2018, 1, 1);
}
}