Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular4 forms - formGroup setValue to model with extra fields

I have a form to update just part of the field of an existing model class in angular 4.

I need to setValue on the current model instance and at the end get the value back updated.

The issue is I need to update only parts of the model but the angular forms returns an error

"Cannot find form control with name 'fieldname'" 

for the extra fields that I do not want to edit.

What is my best option to get the needed behavior?

I thought about adding hidden formControls for the fields I do not want to update in the forms but some of our models are pretty big while we need the user to only edit parts of them.

I have to get an updated model at the end for dirty checking and generic updating of our models (compared to having multiple duplicate class relevant code just for setting the values of all the formControls and updating the models back from the formControls on submit)

Thanks.

UPDATE just for clarification - I want a behavior that is similar to this:

--component.ts
model: Model = someModelWithData;

--component.html
<input type="checkbox" [(NgModel)]="model.FieldOne" />

After the user changes the value in FieldOne, the model is still full with all other data but with FieldOne changed.

like image 383
Royi Mindel Avatar asked Apr 12 '18 13:04

Royi Mindel


People also ask

How do I change FormGroup values?

We use the SetValue to update the FormControl , FormGroup or FormArray . When we use it to update the FormGroup or FormArray the SetValue requires that the object must match the structure of the FormGroup or FormArray exactly. Otherwise, it will result in an error.

What is difference between FormBuilder and FormControl?

In Angular, a reactive form is a FormGroup that is made up of FormControls. The FormBuilder is the class that is used to create both FormGroups and FormControls. I encourage you to check out those links to see the full class definitions of all three.

How do I use FormControl inside FormGroup?

How to add a FormControl to a FormGroup. To add, update, or remove controls in FormGroup , use the following commands: addControl() adds a control and updates its value and validity. removeControl() removes a control.

What is the difference between FormControl and formControlName?

[formControl] assigns a reference to the FormControl instance you created to the FormControlDirective . formControlName assigns a string for the forms module to look up the control by name.


2 Answers

You can update parts of your form with the method patchValue instead of setValue.

this.yourForm.patchValue({
     yourFieldToUpdate: yourValue
});
like image 142
HMarteau Avatar answered Oct 20 '22 12:10

HMarteau


Angular is built in such a way to keep the form model and data model separate.

From the documentation:

In keeping with the reactive paradigm, the component preserves the immutability of the data model, treating it as a pure source of original values. Rather than update the data model directly, the component extracts user changes and forwards them to an external component or service, which does something with them (such as saving them) and returns a new data model to the component that reflects the updated model state.

But if you want to bind to a data model inside of a form, you can set ngModelOptions standalone to true

standalone: Defaults to false. If this is set to true, the ngModel will not register itself with its parent form, and will act as if it's not in the form. This can be handy if you have form meta-controls, a.k.a. form elements nested in the tag that control the display of the form, but don't contain form data.

Stack Blitz Example

In this example, the model has 3 fields, 2 of which can be edited on the form.

model.ts

export class Model {
  fieldOne: string;
  fieldTwo: string;
  fieldThree: string;

  constructor(fieldOne: string, fieldTwo: string, fieldThree: string)
  {
    this.fieldOne = fieldOne;
    this.fieldTwo = fieldTwo;
    this.fieldThree = fieldThree;
  }
}

app.component.ts

import {Component, OnInit} from '@angular/core';
import {AbstractControl, FormBuilder, FormGroup} from '@angular/forms';

import {Model} from './model';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
  private _form
  private _model: Model;

  get form(): FormGroup {
    return this._form;
  }

  get model(): Model {
    return this._model;
  }

  set model(model: Model) {
    this._model = model;
  }

  constructor(private formBuilder: FormBuilder) {}

  ngOnInit() {
    this.model = this.newModel();
    this.createForm();
  }

  private newModel(): Model {
    return new Model('fieldOne', 'fieldTwo', 'fieldThree');
  }

  private createForm() {
    this._form = this.formBuilder.group({
    });
  }
}

app.component.html

As the form values change, the actual data model is updated and only editable fields have been exposed to change via the form.

<form [formGroup]="form">
  <div>
    <label for="fieldOne">Field One</label>
    <input
      id="fieldOne"
      type="text"
      [(ngModel)]="model.fieldOne"
      [ngModelOptions]="{ standalone: true }">
  </div>

  <div>
    <label for="fieldTwo">Field Two</label>
    <input
      id="fieldTwo"
      type="text"
      [(ngModel)]="model.fieldTwo"
      [ngModelOptions]="{ standalone: true }">
  </div>
</form>

<h3>Model</h3>
<pre>{{ model | json }}</pre>
like image 45
josavish Avatar answered Oct 20 '22 11:10

josavish