10

I am trying to create a complex reactive form with nested component that is populated with a data object.

The behavior I am trying to achieve is very similar to the two-way data binding of a template-driven form: when the user edits an input of the form, the data object is changing automatically.

but as opposed to template-driven form, I cannot use [(ngModel)] because it is deprecated in reactive forms for angular V6.

I know that fromGroup.patchValue() will only do a one way binding and then ill have to manually subscribe to change events and update the data object manually - this will result in a lot of tiring code.

Is there any workaround for that scenario?

georgeawg
  • 46,994
  • 13
  • 63
  • 85
Idan Abrashkin
  • 141
  • 2
  • 6
  • Your `form.value` object has already the last form value, why would you need `ngModel` ? – ibenjelloun May 16 '18 at 12:41
  • 4
    form.value will be updated, but not the original source data. for example if I set the value of the 'name' formControl with the value of data['name'], and the user changed the name, the value in data['name'] will still contain the original value. – Idan Abrashkin May 16 '18 at 12:45
  • 1
    i don't know why this change either, now i will need to re verbose code with a lot get and sets that wasn't needed before.. – Hllink Jun 14 '18 at 15:32
  • This is really a step backwards. Reactive forms have no good way to do twoway binding anymore. Seriously, now I have to look a the form values and update the model manually. Especially with nested object modelling that are not easily accessible. Previously I only had to worry once and then do all the databinding. That was it. – Michelangelo Oct 07 '19 at 13:31

2 Answers2

5

Well if I understand you correctly I had a similar problem what I did (I really don't know if this is the best practice)but it's work for me so in the HTML:

<mat-form-field class="mat-container">
    <input matInput  [formControl]="generalDiscount" type="number" 
        formControlName="generalDiscount" 
        (input)="course.amounts.generalDiscount = $event.target.value" <-the workaround 
        placeholder="Discount" required="required">
</mat-form-field>

This input makes it two way binding and in your .ts class you need to put the same field in your form group like

this.amountGroup = this._formBuilder.group({

    [this.course.amounts.fitToNomberOfPeople,Validators.required],
    generalDiscount:[this.course.amounts.generalDiscount,Validators.required],

});

hope that helps

Domenick
  • 1,220
  • 2
  • 8
  • 20
oren
  • 271
  • 1
  • 2
  • 7
  • This is indeed a nice workaround, but I ended up not using Angular forms at all. I am using primitive validations for my fields because the validations are pretty simple. nevertheless, I am a little disappointed that Angular is not offering a better system to handle this situation. – Idan Abrashkin Jun 23 '18 at 18:54
  • I am getting the array of images from http request and pushing into array and displaying using ngfor . for the first set it works and after the page scroll dynamic fetching of images not working. Fetching of text is working dynamically on scroll also Can you tell me why. – Thilak Raj Jun 26 '18 at 05:06
  • This was a life saver for me i tried listening for valueChanges on the form control but that didnt work . – I.Tyger Jul 14 '18 at 12:31
0

Some kind of workaround.

Proposition is to use (input) event. formControl1 updates own value and writes its value to formControl2 with additional '@example.com' text also. Changing formControl2 value updates own value and updates formControl1 with striped '@example.com' text.

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

@Component({
  selector: 'app-template-and-reactive-form',
  template: '<input #inp1 [ngModel]="formControl1.value" ' +
    '(input)="formControl1.setValue(inp1.value);formControl2.setValue(inp1.value+\'@example.com\')" ><br>\n' +
    '<input #inp2 [ngModel]="formControl2.value" ' +
    '(input)="formControl2.setValue(inp2.value);formControl1.setValue(inp2.value.replace(\'@example.com\',\'\'))"><br>\n' +
    'formControl1 value: {{formControl1.value}}<br>\n' +
    'formControl2 value: {{formControl2.value}}<br>',
  styleUrls: ['./template-and-reactive-form.component.scss']
})
export class TemplateAndReactiveFormComponent  {
  formControl1 = new FormControl('');
  formControl2 = new FormControl('');
}
Michal.S
  • 381
  • 3
  • 9