【问题标题】:Angular2 ControlValueAccessorAngular2 ControlValueAccessor
【发布时间】:2016-10-03 04:59:01
【问题描述】:

我正在尝试了解 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”。

所以当我将控件绑定到 SecondControlComponent 时,类似于:

this.form = this.builder.group({
    controlName: this.builder.control(this.theObject) });

在模板的后面:

<second-component ngControl='controlName'> <second-component>

一切正常,因为在 init 上调用 writeValue 并引用现有的 theObject 对象,因此控件修改对象的同一实例(希望我很清楚)

但是:如果我对 FirstControlComponent 执行完全相同的操作,因为该值没有作为引用传递(因为它是一个原始值),并且因为 ControlValueAccessor 不提供“设置器”,我的控件中的值和我的主机组件中的值没有保持同步......

这是否意味着我们必须将 Object 而不是原始的传递给实现 ControlValueAccessor 的自定义控件?我猜不,所以我想我一定是误解了一些东西.. :)

我用对了吗?

欢迎任何提示!

谢谢!

【问题讨论】:

标签: binding angular components controls


【解决方案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 回调

更多详情请参阅这篇文章(“NgModel 兼容组件”部分):

【讨论】:

    【解决方案2】:

    在父组件中,我想要这样的表单输出{someOtherControlName: any, controlName: number},因此子表单的输出必须是数字。也在更新表单中(示例)parentform.patchValue({someOtherControlName: '', controlNmae: 3}) formControl 的值必须正确设置

    @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()
       }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-30
      • 2020-08-17
      • 1970-01-01
      • 2023-04-02
      • 2019-03-27
      • 2021-01-25
      • 2021-12-10
      • 2020-05-26
      相关资源
      最近更新 更多