Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

*ngIf and local template variables

Could someone please explain what's behind the following behavior?

Say we have an Angular 2 component that has a _model object. Then in the template we have this:

<form>
    <input type="text" class="form-control" required [(ngModel)]="_model.firstName" ngControl="test2"  #myInput >
    <br>Class: {{myInput?.className}}
</form>

The _model is available from the beginning being created from scratch in ngOnInit(). The input field is properly populated with the _model.firstName variable and the line:

<br>Class: {{myInput?.className}}

correctly renders the following in the template:

Class: form-control ng-untouched ng-pristine ng-invalid.

So far so good. What confuses me is that the moment I add *ngIf and I change the input field to

<input *ngIf="_model" type="text" class="form-control" required [(ngModel)]="_model.firstName" ngControl="test2"  #myInput >

The double curly braces interpolation stops working because apparently the local myInput variable doesn't get initialized even when nothing else in the code changes, the _model object is still created in onNgInit() and the input field is still working properly. The only thing that the {{myInput?.className}} renders is

Class:

Can someone explain what's going on and/or point me to the correct piece of documentation for this?

EDIT:

Here's a Plunker that shows the issue in question.

Created bug report https://github.com/angular/angular/issues/8087

like image 501
RVP Avatar asked Apr 15 '16 08:04

RVP


People also ask

What is * in * ngIf in Angular?

A shorthand form of the directive, *ngIf="condition" , is generally used, provided as an attribute of the anchor element for the inserted template. Angular expands this into a more explicit version, in which the anchor element is contained in an <ng-template> element.

How do I pass a template reference variable in component?

To get started using template reference variables, simply create a new Angular component or visit an existing one. To create a template reference variable, locate the HTML element that you want to reference and then tag it like so: #myVarName .

What is the difference between ngIf and * ngIf in Angular?

ngIf is the directive. Because it's a structural directive (template-based), you need to use the * prefix to use it into templates. *ngIf corresponds to the shortcut for the following syntax (“syntactic sugar”): <template [ngIf]="condition">

What is * ngIf in HTML?

Definition and Usage. The ng-if directive removes the HTML element if the expression evaluates to false. If the if statement evaluates to true, a copy of the Element is added in the DOM.


1 Answers

We can reference a local template variable on the same element, on a sibling element, or on any child elements. -- ref

*ngIf becomes/expands to

<template [ngIf]="_model">
    <input type="text" class="form-control" required [(ngModel)]="_model.firstName"
     ngControl="test1" #myInput>
</template>

So local template variable #myInput can only be referenced inside the template block (i.e., sibling and/or child elements). Hence you would have to put any HTML that wants to reference the local template variable inside the template:

<template [ngIf]="_model">
   <input type="text" class="form-control" required [(ngModel)]="_model.firstName"
    ngControl="test1"  #myInput >
   <br>Class (this works): {{myInput?.className}}
</template>

Plunker


If you need to show something outside the template block related to the input, use @ViewChildren('myInput') list:QueryList<ElementRef> and then subscribe to changes:

ngAfterViewInit() {
   this.list.changes.subscribe( newList =>
      console.log('new list size:', newList.length)
   )
}

See more QueryList methods in the API doc.

like image 141
Mark Rajcok Avatar answered Sep 21 '22 12:09

Mark Rajcok