Двустороннее связывание в реактивных формах

Используя Angular 2, двусторонняя привязка проста в формах, управляемых шаблонами - вы просто используете синтаксис банановых ящиков. Как бы вы реплицировали это поведение в форме, управляемой моделью?

Например, здесь приведена стандартная реактивная форма. Предположим, что это намного сложнее, чем кажется, с множеством различных входов и бизнес-логики и, следовательно, более подходящим для подхода, ориентированного на модель, чем подход, основанный на шаблонах.

export class ExampleModel {
    public name: string;
    // ... lots of other inputs
}

@Component({
    template: `
        <form [formGroup]="form">
            <input type="text" formControlName="name">
            ... lots of other inputs
        </form>

        <h4>Example values: {{example | json}}</h4>
    `
})
export class ExampleComponent {
    public form: FormGroup;
    public example: ExampleModel = new ExampleModel();

    constructor(private _fb: FormBuilder) {
        this.form = this._fb.group({
            name: [ this.example.name, Validators.required ]
            // lots of other inputs
        });
    }

    this.form.valueChanges.subscribe({
        form => {
            console.info('form values', form);
        }
    });
}

В subscribe() я могу применять все виды логики к значениям формы и отображать их по мере необходимости. Однако я не хочу отображать каждое входное значение из формы. Я просто хочу увидеть значения для всей модели employee по мере ее обновления в подходе, аналогичном [(ngModel)]="example.name", и как показано в json-канале в шаблоне. Как я могу это сделать?

Ответ 1

Примечание: как упомянуто @Clouse24, "Использование Reactive Froms с ngModel устарело в angular 6 и будет удалено в angular 7" (что означает, что ответ ниже не будет поддерживаться начиная с версии 7). Пожалуйста, прочитайте ссылку, чтобы увидеть причины для устаревания и увидеть, какие альтернативы у вас будут.

Вы можете использовать [(ngModel)] с реактивными формами.

<form [formGroup]="form">
  <input name="first" formControlName="first" [(ngModel)]="example.first"/>
  <input name="last" formControlName="last" [(ngModel)]="example.last"/>
</form>

export class App {
  form: FormGroup;
  example = { first: '', last: '' };

  constructor(builder: FormBuilder) {
    this.form = builder.group({
      first: '',
      last: ''
    })
  }
}

Plunker

Это будет совершенно другая директива, чем та, которая будет использоваться без formControlName. С реактивными формами это будет FormControlNameDirective. Без formControlName будет использоваться директива NgModel.

Ответ 2

Иногда вам может потребоваться объединить [(ngModel)] с реактивными формами. Я мог бы быть каким-то элементом управления вводами, который вам не нужен как часть формы, но вам все равно нужно привязать его к контроллеру. Затем вы можете использовать: [(ngModel)]="something" [ngModelOptions]="{standalone: true}"

Ответ 3

Если вы просто хотите показать входное значение, просто создайте переменную во входных данных и используйте ее в своем шаблоне..

.. много других входов
    <h4>Example values: {{ name.value }}</h4>

Ответ 4

Посмотрите это демонстрационное видео, вы получите представление о динамической реактивной форме: https://youtu.be/a-D4rJs49sI

Ответ 5

// Allow two way binding on the [(name)] from the parent component
private nameValue: string;
@Input()
get name() {
    return this.nameValue;
}
set name(values) {
    this.nameValue = values;
    this.nameChange.emit(this.nameValue);
}
@Output() nameChange = new EventEmitter<string>();

ngOnInit() {
    // Update local value and notify parent on control value change
    this.formControl.valueChanges.forEach(value => this.name = value));
}

ngOnChanges() {
    // Update local value on parent change
    this.formControl.setValue(this.expression);
}

Ответ 6

Вот как вы можете решить это:

Чтобы получить результат two-way-binding

Я использую локальные "переменные шаблона" и использую один и тот же formControl для обоих полей.

<form [formGroup]="formGroup">
  <input #myInput (input)="mySlider.value = myInput.value" type="number" formControlName="twoWayControl">

  <mat-slider #mySlider (input)="myInput.value = mySlider.value" formControlName="twoWayControl" min="1" max="100">
  </mat-slider>

</form>

Когда я программно хочу изменить значение модели, я использую setValue() как объявили другие.

  setTo33() {
    this.formGroup.get('twoWayControl').setValue(33);
  }