angular 自定义输入组件未更新
angular custom input component not updating
我为 times 创建了一个自定义输入组件。我可以成功地设置 [(ngModel)] 接收到的初始值,但是不会处理对输入字段的任何更改。
更准确地说:writeValue 最初被调用,setter 没有。
组件如下所示:
@Component({
selector: 'app-timepicker',
templateUrl: './timepicker.component.html',
styleUrls: ['./timepicker.component.scss'],
providers: [{provide: MatFormFieldControl, useExisting: forwardRef(() => NexupTimepickerComponent)}]
})
export class NexupTimepickerComponent implements OnDestroy, ControlValueAccessor {
autofilled: boolean;
// Subject for the changes on the input
stateChanges = new Subject<void>();
// Grouping of the input fields
parts: FormGroup;
public _onChange: any;
constructor(fb: FormBuilder, private fm: FocusMonitor, private elRef: ElementRef<HTMLElement>,
@Optional() @Self() public ngControl: NgControl
) {
this.parts = fb.group({
'hour': '',
'minute': ''
});
// control focus
fm.monitor(elRef.nativeElement, true).subscribe(origin => {
this.focused = !!origin;
this.stateChanges.next();
});
this._onChange = (_: any) => {
};
if (this.ngControl) {
this.ngControl.valueAccessor = this;
}
}
// value
@Input()
get value(): Time | null {
console.log('Getting value');
const n = this.parts.value;
if (n.hour.length === 2 && n.minute.length === 2) {
return new Time(n.hour, n.minute);
}
return null;
}
set value(time: Time | null) {
console.log('Setting value to: ', time);
time = time || new Time('', '');
this.parts.setValue({hour: time.hour, minute: time.minute});
this.stateChanges.next();
}
ngOnDestroy() {
this.stateChanges.complete();
this.fm.stopMonitoring(this.elRef.nativeElement);
}
registerOnChange(fn: any): void {
console.log('registered');
this._onChange = fn;
}
registerOnTouched(fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
}
writeValue(value: any): void {
console.log('received value: ', value);
if ((value !== this.parts.getRawValue()) && value) {
console.log('writing value to: ', value);
this.parts.setValue({hour: value.hour, minute: value.minute});
console.log('new value: ', this.parts.getRawValue());
}
}
}
父组件中的HTML是这样的:
<mat-form-field appearance="outline">
<mat-label>End Time</mat-label>
<app-timepicker [required]="true"
[(ngModel)]="endTimeObject" #endTime="ngModel" name="endTime" ngDefaultControl>
</app-timepicker>
</mat-form-field>
如果 setter: set value 没有被调用,这通常是因为你没有改变 "value" 值,你应该做点什么像 this.value = "...";
为了做到这一点和更多的控制,我通常在我的组件的内部输入上添加一个 [formControl]="myControl"(如果我有一个:))并在组件中做这样的事情:
myControl = new FormControl();
this.myControl.onStatusChange.subscribe( (newValue) => {
this.value = newValue;
});
此外,[(ngModel)] 不会更新到最新是正常的,因为您永远不会调用 this._onChange() 回调。
registerOnChage 方法为您提供了一个回调,当您从组件内部更新值时必须调用该回调以通知 ngModel/formControl。我想你应该添加设定值:
set value(time: Time | null) {
console.log('Setting value to: ', time);
time = time || new Time('', '');
const newValue = {hour: time.hour, minute: time.minute};
this.parts.setValue(newValue );
this._onChange(newValue); // call the callback :)
this.stateChanges.next();
}
有关更多信息,您可以在此处找到 controlValueAccessor 的默认实现。您可以在每个使用 ngModel 的组件中扩展此 class 并简单地更改值 (this.value = 'newValue') 并覆盖 writeValue 导致它通常需要更改以满足您的组件需求。
https://github.com/xrobert35/asi-ngtools/blob/master/src/components/common/default-control-value-accessor.ts
我为 times 创建了一个自定义输入组件。我可以成功地设置 [(ngModel)] 接收到的初始值,但是不会处理对输入字段的任何更改。 更准确地说:writeValue 最初被调用,setter 没有。
组件如下所示:
@Component({
selector: 'app-timepicker',
templateUrl: './timepicker.component.html',
styleUrls: ['./timepicker.component.scss'],
providers: [{provide: MatFormFieldControl, useExisting: forwardRef(() => NexupTimepickerComponent)}]
})
export class NexupTimepickerComponent implements OnDestroy, ControlValueAccessor {
autofilled: boolean;
// Subject for the changes on the input
stateChanges = new Subject<void>();
// Grouping of the input fields
parts: FormGroup;
public _onChange: any;
constructor(fb: FormBuilder, private fm: FocusMonitor, private elRef: ElementRef<HTMLElement>,
@Optional() @Self() public ngControl: NgControl
) {
this.parts = fb.group({
'hour': '',
'minute': ''
});
// control focus
fm.monitor(elRef.nativeElement, true).subscribe(origin => {
this.focused = !!origin;
this.stateChanges.next();
});
this._onChange = (_: any) => {
};
if (this.ngControl) {
this.ngControl.valueAccessor = this;
}
}
// value
@Input()
get value(): Time | null {
console.log('Getting value');
const n = this.parts.value;
if (n.hour.length === 2 && n.minute.length === 2) {
return new Time(n.hour, n.minute);
}
return null;
}
set value(time: Time | null) {
console.log('Setting value to: ', time);
time = time || new Time('', '');
this.parts.setValue({hour: time.hour, minute: time.minute});
this.stateChanges.next();
}
ngOnDestroy() {
this.stateChanges.complete();
this.fm.stopMonitoring(this.elRef.nativeElement);
}
registerOnChange(fn: any): void {
console.log('registered');
this._onChange = fn;
}
registerOnTouched(fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
}
writeValue(value: any): void {
console.log('received value: ', value);
if ((value !== this.parts.getRawValue()) && value) {
console.log('writing value to: ', value);
this.parts.setValue({hour: value.hour, minute: value.minute});
console.log('new value: ', this.parts.getRawValue());
}
}
}
父组件中的HTML是这样的:
<mat-form-field appearance="outline">
<mat-label>End Time</mat-label>
<app-timepicker [required]="true"
[(ngModel)]="endTimeObject" #endTime="ngModel" name="endTime" ngDefaultControl>
</app-timepicker>
</mat-form-field>
如果 setter: set value 没有被调用,这通常是因为你没有改变 "value" 值,你应该做点什么像 this.value = "...";
为了做到这一点和更多的控制,我通常在我的组件的内部输入上添加一个 [formControl]="myControl"(如果我有一个:))并在组件中做这样的事情:
myControl = new FormControl();
this.myControl.onStatusChange.subscribe( (newValue) => {
this.value = newValue;
});
此外,[(ngModel)] 不会更新到最新是正常的,因为您永远不会调用 this._onChange() 回调。
registerOnChage 方法为您提供了一个回调,当您从组件内部更新值时必须调用该回调以通知 ngModel/formControl。我想你应该添加设定值:
set value(time: Time | null) {
console.log('Setting value to: ', time);
time = time || new Time('', '');
const newValue = {hour: time.hour, minute: time.minute};
this.parts.setValue(newValue );
this._onChange(newValue); // call the callback :)
this.stateChanges.next();
}
有关更多信息,您可以在此处找到 controlValueAccessor 的默认实现。您可以在每个使用 ngModel 的组件中扩展此 class 并简单地更改值 (this.value = 'newValue') 并覆盖 writeValue 导致它通常需要更改以满足您的组件需求。 https://github.com/xrobert35/asi-ngtools/blob/master/src/components/common/default-control-value-accessor.ts