1
votes

I have a pretty basic autocomplete set up with Angular Material (6). Here is the basic implementation:

<mat-form-field>
    <input type="text" matInput placeholder="Company" formControlName="company" [matAutocomplete]="autoCo"/>
    <mat-autocomplete #autoCo="matAutocomplete" [displayWith]="displayCo">
        <mat-option *ngFor="let company of filteredCompanies | async" [value]="company">
            {{ company.companyName }}
        </mat-option>
    </mat-autocomplete>
</mat-form-field>

That works without a problem. However, I want to have something happen when a selection is made. To do this, I added (optionSelected)="onSelectionChanged($event)" to the mat-autocomplete element. Initially, everything works as expected (filtering the options works). When a selection has been made, the onSelectionChanged function also fires as expected.

However, after a selection has been made, the selected item is the only item available in the autocomplete drop-down no matter what changes I make. So even if I delete all the text in the input, I still only see the previously selected option. I would expect to see the complete list instead.

In ngOnInit, I have:

this.filteredCompanies = this.companyForm.get("company").valueChanges.pipe(
        debounceTime(200))
        .pipe(mergeMap(val => this.filter(val)));

It appears that the valueChanges subscription ends if I bind to optionSelected. If I don't bind to optionSelected, the list of options updates as expected.

Am I incorrectly binding to the optionSelected event? Do I have to re-subscribe to the form valueChanges from within onSelectionChanged()?? If so, why?

For what it is worth, here is some other relevant code:

@Output()
optionSelected = new EventEmitter();

onSelectionChanged(event: any) {
    console.log(event);
    this.optionSelected.emit(event);
}
2

2 Answers

1
votes

To try and answer your question, I first attempted to reproduce the problem. I created the following:

StackBlitz.

I had to make a number of assumptions for code that you did not include, but for the code you did include I did not substantively modify it (other than to add the occasional console.log).

As you can see in the StackBlitz, the problem you are describing does not occur.

This could be related to code you have not shared. Please compare the StackBlitz with your code. If there is a difference, please share the different code and I will update the StackBlitz to re-test.

Some notes:

  • I just used the default 'hello-component' for your code.
  • I created a simple filter() method since you did not provide code for that.
  • I created a simple displayCo() method since you didn't provide this code.
  • I assumed that the parent component supplied the list of options to this child component through an Input called companies, which is a Company[].
  • I also made a number of assumptions on how you created your form, since that also was not included in your question.

I hope this will help get to the root cause of your issue.

Update

Your code from the edited StackBlitz you supplied in the comments below is calling:

this.companyForm.setControl("company", this.setCompany(newSelection));

But this.setCompany returns a FormGroup and .setControl() needs a FormControl as the second parameter. You should be able to simply update the existing FormGroup with something like this:

this.companyForm.get('company').setValue(newSelection);

Updated StackBlitz here.

0
votes

Are you actually subscribing to valueChanges? From your code it doesn't look like it. I think you are missing a .subscribe() call.

this.filteredCompanies = this.companyForm.get("company").valueChanges
  .pipe(debounceTime(200))
  .pipe(mergeMap(val => this.filter(val)))
  .subscribe(() => {});

Also your binding to onSelectionChanged is somewhat wrong, this:

@Output()
optionSelected = new EventEmitter();

onSelectionChanged(event: any) {
  console.log(event);
  this.optionSelected.emit(event);
}

can be simplified to:

onSelectionChanged(event: any) {
  console.log(event);
  // do what you want here
}