我正在尝试用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
已导入每个模块(应用模块中为ngbModule.forRoot()
),FormsModule
始终在NgbModule
之前导入。
Angular版本5.2.3
ng-bootstrap版本1.02
感谢任何帮助。
答案 0 :(得分:2)
您需要在DatePickerPopupComponent上实现ControlValueAccessor。这将允许角形式(模板或反应)模型与组件绑定。你的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);
}
}