javascriptangularangular2-forms

What is #auto attribute here and why it is required


I am trying to learn angular material 2 and came across this #auto attribute in autocomplete.I understand auto can be replaced with any text, but why there need a # here before auto and what is there any name of this attribute?

<md-input-container>
  <input mdInput placeholder="State" [mdAutocomplete]="auto" [formControl]="stateCtrl">
</md-input-container>

<md-autocomplete #auto="mdAutocomplete">
               ^^^^ what is name of this property
  <md-option *ngFor="let state of filteredStates | async" [value]="state">
    {{ state }}
  </md-option>
</md-autocomplete>

Solution

  • It is a template reference variable that allows us to get reference to html element or something else if we declare directive on this element.

    We can declare template reference variable via (1)

    #Default behavior

    In most cases, Angular sets the reference variable's value to the html element on which it was declared (2) .

    <div #divElem></div>
    <input #inputEl>
    <table #tableEl></table>
    <form #formEl></form>
    

    In the preceding all template reference variables will refer to the corresponding elements.

    #divElem     HTMLDivElement
    #inputEl     HTMLInputElement
    #tableEl     HTMLTableElement
    #formEl      HTMLFormElement
    

    #Directives can change default behavior

    But a directive can change that behavior and set the value to something else, such as itself.

    Angular assigns references with empty value to component (3)

    If we have component like:

    @Component({
      selector: '[comp]',
      ...
    })
    export class SomeComponent {}
    

    and template as:

    <div comp #someComp></div>
    

    then #someComp variable will refer to component itself (SomeComponent instance).

    Angular doesn't locate directives in references with empty value (4)

    If we change @Component decorator to @Directive

    @Directive({
      selector: '[comp]',
      ...
    })
    export class SomeDirective {}
    

    then #someComp variable will refer to HTMLDivElement.

    How we can get SomeDirective instance in this case?

    Fortunately, Template reference variable can have value (5)

    We can define exportAs property within @Component/@Directive decorator (6):

    exportAs is a name under which the component instance is exported in a template. Can be given a single name or a comma-delimited list of names.

    @Directive({
      selector: '[comp]',
      exportAs: 'someDir',
      ...
    })
    export class SomeDirective {}
    

    and then use exportAs value as value for template reference variable within template (7):

    <div comp #someComp="someDir"></div>
    

    After that #someComp will refer to our directive.

    Now let's imagine we have several directives applied to this component. And we want to get specific directive instance.exportAs property is a good choice to solve this problem.


    Let's go back to your code

    If you open source code of MdAutocomplete component you can see:

    @Component({
      ...
      exportAs: 'mdAutocomplete'
    })
    export class MdAutocomplete {
      ...
    

    Since in your template you have

    #auto="mdAutocomplete"

    Then #auto variable will refer to instance of MdAutocomplete component. This reference is used in MdAutocompleteTrigger directive:

    @Directive({
      selector: 'input[mdAutocomplete], input[matAutocomplete],' +
                'textarea[mdAutocomplete], textarea[matAutocomplete]',
      ...
    })
    export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
      @Input('mdAutocomplete') autocomplete: MdAutocomplete;
    

    because you're passing auto variable to input within template

    <input mdInput placeholder="State" [mdAutocomplete]="auto"
    

    We can omit value and use only variable name in this case like

    <md-autocomplete #auto>
    

    but

    So prefer specifying value for template reference variable if you doubt what it will refer to.