使用ControlValueAccessor - 值与两个值源不同步

时间:2018-03-17 13:20:48

标签: angular

我正在构建自己的自定义输入字段。我想使用ControlValueAccessorFormGroupFormControlName以及ngModel一起使用。

问题是我在一个表单中有两个输入字段。这些输入不同步,但FormGroup值同步。

以下是示例应用:https://stackblitz.com/edit/angular-9krudy

如果您在输入字段中更改值,则它不会反映在组件的值上,而是反映在FormGroup值中。

如果使用my-input组件更改值("随机更改值"按钮),则会更改组件中的值,但不会更改输入中的值。如前所述,FormGroup中的值正在发生变化。

当我使用FormGroup更改patchValue值时,一切正常。

如何修复我的代码以始终保持同步? 我希望my-inputngModel一起使用,因此传递FormGroup并且取决于它不是一种选择。

修改

我发现在Angular 您不能拥有两个具有相同formNameControl 的输入字段:https://stackblitz.com/edit/angular-y2sj5g(好的,你可以但他们可以不同步)。所以这个问题无效。

编辑:代码

AppComponent:

import { Component } from '@angular/core';
import {FormControl, FormGroup} from "@angular/forms";

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  formGroup: FormGroup = new FormGroup({
        text: new FormControl('text')
    });

    constructor() {
    }

    ngOnInit() {
    }

    onChange() {
        this.formGroup.get('text')
            .patchValue('New value');
    }
}

AppComponentHtml

<form [formGroup]="formGroup">
    <input type="text" [formControlName]="'text'">
    <my-input [formControlName]="'text'"></my-input>
</form>

MyInputComponent:

import {Component, forwardRef, OnInit} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms";

@Component({
    selector: 'my-input',
    template: `<hr>
In component
<p>
    <a (click)="onChange()" href="javascript:void(null)">Change value randomly</a>
</p>
Value in component: <b>{{value}}</b>
<hr>`,
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => MyInputComponent),
            multi: true
        }
    ]
})
export class MyInputComponent implements ControlValueAccessor, OnInit {
    protected _value: any;

    constructor() {
    }

    ngOnInit() {
    }

    onChange() {
        this.value = Math.random();
    }

    get value(): any {
        return this._value;
    }

    set value(value: any) {
        this._value = value;
        this.propagateChange(this._value);
    }

    writeValue(value: any) {
        console.log('Out from component', value);
        if (value !== undefined) {
            this._value = value;
        }
    }

    propagateChange = (_: any) => {
    };

    registerOnChange(fn) {
        this.propagateChange = fn;
    }

    registerOnTouched() {
    }
}

2 个答案:

答案 0 :(得分:0)

您的代码存在两个问题:

  1. 您的my-input组件应在其模板中包含输入元素

    @Component({
      selector: 'my-input',
      template: `
        <input [value]="value" 
               (change)="onValueChanged($event)" 
               (keyup)="onValueChanged($event)"/>
    ...
    

    其中onValueChanged方法用于设置存储在组件中的值

    onValueChanged(event) {
      this.value = event.target.value;
    }
    
  2. 您有两个具有相同formControlName值的表单控件。将其更改为其他内容,例如

    <form [formGroup]="formGroup">
        Input: <input formControlName="otherInput"/> <br/>
        My input: <my-input formControlName="text"></my-input>
    </form>
    
    
    formGroup: FormGroup = new FormGroup({
        text: new FormControl('text'),
        otherInput: new FormControl('otherText')
    });
    
  3. 工作演示:https://stackblitz.com/edit/angular-t3qbaz?file=app/app.component.ts

答案 1 :(得分:0)

我发现在Angular中你不能有两个具有相同formNameControl的输入字段:https://stackblitz.com/edit/angular-y2sj5g(好的,你可以,但它们不同步)。所以这个问题无效。

修改 这是Angular's功能:https://github.com/angular/angular/issues/10036