Search code examples
angularangular-directiveangular-ngmodel

How exactly works ngModel directive in this use case?


I am a complete beginner with Angular and I have some conceptual doubts about the NgModel directive and its possibile use cases.

Reading on the Angular official documentation: https://angular.io/api/forms/NgModel

I can read only:

Creates a FormControl instance from a domain model and binds it to a form control element.

It seems to me that this FormControl should be an object holding the values inserted into my form fields and the related fields status (for example for validation pourpose). Is it correct? Now I have some doubt on concrete use cases.

So lets do an example.

I have this form:

<form (ngSubmit)="onSubmit(form)" #form="ngForm">
  <div class="form-group">
    <label for="name">Character Name</label>
    <input
      type="text"
      id="name"
      name="name"
      class="form-control"
      ngModel
      required
      #nameCtrl="ngModel">
    <span class="help-block" *ngIf="nameCtrl.invalid && nameCtrl.touched">Please, enter a name!</span>
  </div>

  <div class="form-group">
    <label for="side">Chose Side</label>
    <select name="side" id="side" class="form-control" ngModel>
      <option *ngFor="let option of availableSides" [value]="option.value">
        {{ option.display }}
      </option>
    </select>
  </div>

  <button class="btn btn-primary" type="submit" [disabled]="form.invalid">Add Character</button>
</form>
  1. On my parent form element I have: #form="ngForm". What exactly indicates? From what I can understand it is simply creating a reference of the entire form into the form "object"\reference.

  2. Then I have this input field inside my form:

Here ngModel appear twice:

Why I have a first ngModel? What it exactly means?

The second time that appear is #nameCtrl="ngModel" that should simply create a reference of this input field into the nameCtrl "address".


Solution

  • NgModel directive creates a FormControl instance from a domain model and binds it to a form control element. That's right.

    In all examples below NgModel directive is applied to input element.

    <input name="name" ngModel>
    
    <input name="name" [ngModel]="someValue">
    
    <input name="name" [(ngModel)]="someValue">
    

    It means that for each element above Angular will create an instance of NgModel class.

    Internally this class holds a new instance of FormControl

     public readonly control: FormControl = new FormControl(); 
    

    which value is updated and synced subsequently with model, input element and the rest form if needed .

    Next thing you need to understand is template reference variable(#var)

    This variable helps us to get hold of reference to some instance: either HTMLElement or Angular Component/Directive/Service.

    Template reference variable can have a value #var="exportAsValue". This allows us to get reference to specific instance, e.g. we added to directives to an elements and want our template reference variable to refer to the first directive.

    For this case we need to define exportAs property in @Directive decorator definition:

    @Directive({
      selector: '[myDir]',
      exportAs: 'myCoolDir'
    })
    export class MyDir {
      someProp: string;
    }
    

    Now, we can get reference to MyDir instance by using the following snippet:

    <div myDir #someRef="myCoolDir">
       {{ someRef.someProp }}
    

    Back to your example:

    • #form="ngForm" holds a reference to NgForm class

    • #nameCtrl="ngModel" holds a reference to NgModel class

    This means that you can access to any properties/methods of those classes like nameCtrl.invalid or form.invalid

    See also: