Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

About concept of ngForm and ngModel in template driven forms in angular

Hello I have recently ventured into angular and ionic development.

I understand that interpolation and property binding is to pass data from class to template, and that interpolation supports only strings, whereas property binding supports all types.

Event binding is used to pass data from template into class.

Two way binding is achieved using foll. 4 ways:

  1. With ngModel banana syntax:
<input [(ngModel)]="username">
<p>Hello {{username}}!</p>
  1. NgModel without banana syntax:
<input [ngModel]="username" (ngModelChange)="username = $event">
<p>Hello {{username}}!</p>
  1. Without ngModel:
<input [value]="username" (input)="username = $event.target.value">
<p>Hello {{username}}!</p>

Or

<input [value]="username" (input)="username = varTest.value" #varTest>
<p>Hello {{username}}!</p>
  1. We can implement custom two way binding (without ngModel) provided we implement appropriate functions:
<custom-counter [(counter)]="someValue"></custom-counter>
<p>counterValue = {{someValue}}</p>

We also have a concept of template reference variables. When you declare this on say an input field, the value of field is accessible in the template using interpolation. Also, if ngModel is assigned to template ref variable.. #varTref="ngModel", then various properties of the element like validation, dirty, pristine, touched, untouched is accessible in template using interpolation. All these can be passed to the code class file by passing the template ref variable into say for example a button click event OR we can make use of ViewChild concept.

My question is about ngForms and ngModel concept in case of forms (template driven forms):

  1. We use <form #f="ngForm"..... And then in each input element we use ngModel with a name and this makes it accessible as property of forms.value.fieldname. Can the same thing not be achieved just by using template reference variable and then passing this to the button click event, thus having access to the form elements in the code? Then why do we have to use ngForm concept?

  2. At element level we use ngModel. Is this same as attribute binding or event binding? Or is it just to make the element accessible to the #f? We could as well use template reference variable to achieve the same isnt it? To achieve two way binding we make use of banana syntax here too so what purpose does just using the keyword ngModel at every element level really serve in template driven forms?

  3. Is using [(ngModel)]=varName same as writing [(ngModel)] name=varName?

Please I need some clarity in this. Thanks.

like image 999
variable Avatar asked Dec 09 '18 06:12

variable


People also ask

What is ngModel and NgForm in Angular?

NgModel. Reconciles value changes in the attached form element with changes in the data model, allowing you to respond to user input with input validation and error handling. NgForm. Creates a top-level FormGroup instance and binds it to a <form> element to track aggregated form value and validation status.

What is Angular NgForm?

*ngFor is a predefined directive in Angular. It accepts an array to iterate data over atemplate to replicate the template with different data. It's the same as the forEach() method in JavaScript, which also iterates over an array.

Why do we use NgForm in Angular?

NgForm is used to create a top-level form group Instance, and it binds the form to the given form value. NgModule: Module used by NgForm is: FormsModule.

What is template driven in Angular?

A template-driven form is the simplest way to build a form in Angular. It uses Angular's two-way data-binding directive (ngModel) to create and manage the underlying form instance. Additionally, as the name suggests, a template form is mainly driven by the view component.


1 Answers

Yes, these concepts can be confusing at first. But some of the information you specified above regarding two-way binding is incorrect:

Two-way binding

[(ngModel)]="lastName"

Any modification to the component property is shown in the template and any change in the template is set in the component property. This is most often used on input boxes and for template driven forms.

The above is a "short-cut" version of this:

<input [ngModel]="lastName" (ngModelChange)="lastName = $event">

One way/property binding

[ngModel]="lastName"

The UI is kept in sync with the value of the component property. This one is similar to interpolation: {{lastName}}

One time binding

ngModel="lastName"

Only binds the initial value of the component property and won't change if the value changes.

Template Reference Variables

#lastNameVar="ngModel"    /* for a form model element eg input element*/
#f="ngForm"               /* for the form itself */

The primary purpose of a template reference variable is to provide a reference to an item in the template. You don't need to add it to every input element on a template driven form, only those that you want to access.

For example:

  <div class="form-group row mb-2">
    <label class="col-md-2 col-form-label"
           for="lastNameId">Last Name</label>
    <div class="col-md-8">
      <input class="form-control"
             id="lastNameId"
             type="text"
             placeholder="Last Name (required)"
             required
             maxlength="50"
             [(ngModel)]="customer.lastName"
             name="lastName"
             #lastNameVar="ngModel"
             [ngClass]="{'is-invalid': (lastNameVar.touched || lastNameVar.dirty) && !lastNameVar.valid }" />
      <span class="invalid-feedback">
        <span *ngIf="lastNameVar.errors?.required">
          Please enter your last name.
        </span>
        <span *ngIf="lastNameVar.errors?.maxlength">
          The last name must be less than 50 characters.
        </span>
      </span>
    </div>
  </div>

Notice how the above sets the template reference variable to #lastName and then uses it to set the style (with [ngClass]) and to check the errors collection to display the appropriate error message.

Or for your example with the form, you can check the form state to disable the Save button, for example:

      <button class="btn btn-primary"
              type="submit"
              [disabled]="!f.valid">
        Save
      </button>

If you have no need to access the state of the form in your template, you don't need the template reference variable.

You can also pass the form's template reference variable into the component to access the form value or state:

In the template:

<form novalidate
      (ngSubmit)="save(signupForm)"
      #signupForm="ngForm">

In the component:

  save(customerForm: NgForm) {
    console.log('Saved: ' + JSON.stringify(customerForm.value));
  }

You could instead pass in each individual control's template reference variable, but why? As you add controls over time, you'd have to remember to always add it to the method call. And you'd have to check each control's state instead of just the form's overall state. It is much easier/better/clearer to simply pass the reference to the form.

<form novalidate
      (ngSubmit)="save(lastName, firstName, phone, email)">
like image 114
DeborahK Avatar answered Sep 29 '22 12:09

DeborahK