4
votes

Can someone please explain to me how does the MatAutocompleteTrigger work?

@ViewChild('autocompleteInput', { read: MatAutocompleteTrigger }) triggerAutocompleteInput: MatAutocompleteTrigger;

<mat-form-field>
  <input
    #autocompleteInput
    matInput
    placeholder="Label"
    formControlName="label"
    [matAutocomplete]="autocompletePanel"
  >
</mat-form-field>

<mat-autocomplete #autocompletePanel="matAutocomplete" [displayWith]="displayFn">
  <mat-option
    *ngFor="let item of items | async"
    [value]="item.label"
  >
    {{ item.label }}
  </mat-option>
</mat-autocomplete>

this.triggerAutocompleteInput.optionSelections.subscribe(option => {
      console.log('Im gonna kill myself', option );
    });

It doesn't do anything. I can be selecting options all day long and nothing will fire. Shouldn't the subscription receive data when I click some option? The this.triggerAutocompleteInput.panelClosingActions works only when you have the autocomplete panel active and you close it with blur.

I don't understand the behavior and I don't understand the documentation.

And what about if you need to access the input through nativeElement? You can't do it when you use it as MatAutocompleteTrigger as far as I can tell.

I'm going crazy.

1

1 Answers

2
votes

First off, some preface:

MatAutocompleteTrigger functions primarily as a template directive. It 'holds' the input element and provides a point to render the MatAutocomplete options defined elsewhere.

optionSelections will emit a stream of values, but it won't emit null values. It's a stream that comes from the MatAutocompleteComponent. In your component, you'll want to subscribe to the emitter afterContentInit, when the autocomplete components have finished their own lifecycle logic.

Next, it looks like you're binding [value] to let item.label. You don't need to put the let in there; this is just declaring an unassigned variable and is equivalent to being null. Since optionSelections emits this [value] associated with the option, and since the value passed here is null, you won't get any emissions.

Lastly, since the options selections are known to the MatAutocompleteComponent but only passed by reference to the MatAutocompleteTrigger, it's my opinion that it's better to get these events from the MatAutocompleteComponent, partly because those properties belong to that component, but mostly because MatAutocompleteComponent has its own (optionSelected) EventEmitter that can be template-bound:

<mat-form-field>
  <input
    #autocompleteInput
    matInput
    placeholder="Label"
    formControlName="label"
    [matAutocomplete]="autocompletePanel"
  >
</mat-form-field>

<mat-autocomplete #autocompletePanel="matAutocomplete" [displayWith]="displayFn" (optionSelected)="doStuff($event)">
  <mat-option
    *ngFor="let item of items | async"
    [value]="item.label"
  >
    {{ item.label }}
  </mat-option>
</mat-autocomplete>


public doStuff(e: MatAutocompleteSelectedEvent) { /* stuff */ }

Also, you have exercise.label bound to the <mat-option> template value. Not sure if that's a typo, but in your provided code exercise isn't defined anywhere.