我试图了解ControlValueAccessor如何正确工作。
我用两种不同的控制组件研究了它的行为:
简而言之:
class FirstControlComponent implements ControlValueAccessor {
// ...
value:number = 10;
writeValue(value: number) {
this.value = value;
}
// ...
}
class SecondControlComponent implements ControlValueAccessor {
// ...
value:any = {};
writeValue(value: any) {
this.value = value;
}
// ...
}
ControlValueAccessor界面仅指定' setter': writeValue ,但没有' getter'。
因此,当我将Control绑定到SecondControlComponent时,类似于:
this.form = this.builder.group({
controlName: this.builder.control(this.theObject) });
以及稍后的模板:
<second-component ngControl='controlName'> <second-component>
一切正常,因为在init上调用了writeValue并引用了现有的theObject对象,因此控件修改了对象的同一个实例(希望我明白)
BUT:如果我使用FirstControlComponent执行完全相同的操作,因为该值不作为参考传递(因为它是原始的),并且< strong>因为 ControlValueAccessor不提供&#39; setter&#39;我的控件中的值和主机组件中的值不保持同步...
这是否意味着我们必须将Object而不是原语传递给实现ControlValueAccessor的自定义控件?我猜不,所以我想我一定是误会了......:)
我正确地使用它吗?
欢迎任何提示!
谢谢!
答案 0 :(得分:1)
我不清楚你在这里尝试做什么,但ControlValueAccessor
是你需要为你的元素注册的实体。这样的事情:
const CUSTOM_VALUE_ACCESSOR = new Provider(
NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => LabelsValueAccessor), multi: true});
@Directive({
(...)
providers: [CUSTOM_VALUE_ACCESSOR]
})
export class LabelsValueAccessor implements ControlValueAccessor {
(...)
}
然后它将获取部分值更新(来自组件和模板)。在输入中的组件中设置值时(例如),在值访问器中调用writeValue
方法。如果要更新值访问器的输入值,则需要利用Angular2注册的onChange回调
有关更多详细信息,请参阅此文章(与#34; NgModel兼容的组件&#34;部分):
答案 1 :(得分:0)
在“父组件”中,我希望输出类似{someOtherControlName: any, controlName: number}
的形式,因此“子”形式的输出必须是数字。还要以更新形式(例如),必须正确设置formControl的parentform.patchValue({someOtherControlName: '', controlNmae: 3})
值
@Component({
selector: 'parent',
template: `
<div [formGroup]="form">
<second-component [formControl]='form.controlName'> <second-component>
<div formControlName="someOtherControlName"></div>
export class ParentComponent {
parentForm = new FormGroup({
controlName: new FormControl(), <<<<<======important
someOtherControlName: new FormControl()
})
}
在ControlValueAccessor中:
@Component({
selector: 'counter',
template: `
<div class="number-input" [formGroup]="form">
<input type="text" class="form-control text-center" formControlName="counter" />
</div>
`,
styleUrls: ['counter.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: CounterComponent,
multi: true,
},
],
})
export class CounterComponent implements ControlValueAccessor, OnDestroy, OnInit {
form = new FormGroup({
counter: new FormControl(0, Validators.required),
})
private onChange: (value: any) => void = value => {}
private onTouched: () => void = () => {}
myValue: number
private onDestroy$: Subject<void> = new Subject()
ngOnInit() {
this.form.valueChanges
.pipe(
tap(value => {
this.onChange(typeof value === 'number' ? value : value.counter) <<<< important
this.onTouched()
}),
takeUntil(this.onDestroy$)
)
.subscribe()
}
}
writeValue(value: number | { counter: number }) {
this.myValue = typeof value === 'number' ? value : value.counter
this.form.setValue({ counter: value > 0 ? value : 0 })
}
registerOnChange(fn: () => {}) {
this.onChange = fn
}
registerOnTouched(fn: () => {}) {
this.onTouched = fn
}
setDisabledState?(isDisabled: boolean): void {
// when the parent updates the
// state of the form control
if (isDisabled) {
this.form.disable()
} else {
this.form.enable()
}
}
ngOnDestroy(): void {
this.onDestroy$.next()
this.onDestroy$.complete()
}