'Two way data binding in model driven forms

I have a reactive form, in which, i have a first name, a last name and finally display name textbox. When i give first name and last name, the value of the display name textbox should contains first name and second name concatenated. But as i'm still in learning stage, couldn't able to figure out what is wrong with this code. Any advice would be helpful. Thank you.

Here is my code

  <form [formGroup]="myForm" novalidate (ngSubmit)="save(myForm.value, myForm.valid)">
    <div class="form-group">
      <label for="">First Name</label>
      <input type="text" class="form-control" formControlName="firstname" [(ngModel)]="firstname">
    </div>
    <div class="form-group">
      <label for="">Last Name</label>
      <input type="text" class="form-control" formControlName="lastname" [(ngModel)]="secondnamename">
    </div>
    <div class="form-group">
      <label for="">Display Name</label>
      <input type="text" class="form-control" formControlName="displayname" value='{{firstname}}{{lastname}}'>
    </div>
    <div class="margin-20">
      <div>myForm details:-</div>
      <pre>myForm value: <br>{{myForm.value | json}}</pre>
    </div>
  </form>

Here is my plnkr

Gif:

enter image description here



Solution 1:[1]

You can also take the more "reactive" approach and listen to changes of the form like:

   this.myForm.valueChanges.subscribe((form) => {
     this.displayname = `${form.firstname} ${form.secondname}`;
   });

Then you can even get rid of the unnecessary two-way data-binding (and the corresponding local state) you use for firstname and secondname like that. See the Plunker: https://plnkr.co/edit/h5aFRDTWfj0gQ69CvVK7?p=preview

Solution 2:[2]

Something like this should work (after: https://angular.io/docs/ts/latest/guide/user-input.html)

In your template:

 <div class="form-group">
  <label for="">First Name</label>
  <input type="text" class="form-control" formControlName="firstname" [(ngModel)]="firstname" (keyup)="onKey($event)>
</div>
<div class="form-group">
  <label for="">Last Name</label>
  <input type="text" class="form-control" formControlName="lastname" [(ngModel)]="secondname" (keyup)="onKey($event)>
</div>
<div class="form-group">
  <label for="">Display Name</label>
  <input type="text" class="form-control" formControlName="displayname" value='{{displayname}}'>
</div>

In your component.ts:

onKey(event:any) { 
displayname = firstname + ' ' + secondnamename;
}

Solution 3:[3]

For you first issue Display name is not updating second name-

that's because you are you are having typo there , you have to have the model value there not formControlName check the code update planker

 <form [formGroup]="myForm" novalidate (ngSubmit)="save(myForm.value, myForm.valid)">
    <div class="form-group">
      <label for="">First Name</label>
      <input type="text" class="form-control" formControlName="firstname" [(ngModel)]="firstname">
    </div>
    <div class="form-group">
      <label for="">Last Name</label>
      <input type="text" class="form-control" formControlName="lastname" [(ngModel)]="secondnamename">
    </div>
    <div class="form-group">
      <label for="">Display Name</label>
      <input type="text" class="form-control" formControlName="displayname" value='{{firstname}} {{secondnamename}}'> //change in this line
    </div>
    <div class="margin-20">
      <div>myForm details:-</div>
      <pre>myForm value: <br>{{myForm.value | json}}</pre>
    </div>
  </form>

And you updating the form value you have of Display Name you have to fire some event like

this.element.nativeElement.dispatchEvent(new Event('input'));

or any other events(onBlur,onClick,onFocus for the first two text boxes) in the component.

Solution 4:[4]

You have to change your displayname input like this.

 <input type="text" class="form-control" formControlName="displayname" [ngModel]=firstname+secondname> 

This way you will have a one way binding to firstname and secondname in that input.

Second thing you need to change is your app.component.ts like this:

firstname:string = '';
secondname:string = '';

Just add a empty string and you are good to go.

Solution 5:[5]

Regarding the solution from 2016, Angular API docs as of the time of this answer say:

Use with ngModel is deprecated

Support for using the ngModel input property and ngModelChange event with reactive form directives has been deprecated in Angular v6 and is scheduled for removal in a future version of Angular.

For details, see Deprecated features.

As per the second link, it is encouraged to use reactive forms patterns; as in:

<input [formControl]="control">

for the template, and

this.control.setValue('some value');

for the component model.


In this question's scenario, the following line
<input type="text" class="form-control" formControlName="displayname">

would thus be replaced with its FormControl object, which for clarity's sake I'll assume to be called dname and hence connected as follows:

<input type="text" class="form-control" [formControl]="dname">

then its value set in the component model through:

this.dname.setValue(this.fname.value + this.lname.value)

which is to be called on the event where you want to change the display name control (for example, could be the subscriber function on the value change observable for the first and last name controls) where also for clarity's sake I'll assume their respective names (as used above) in the component model be fname and lname.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 theotherdy
Solution 3
Solution 4 user2959870
Solution 5