3

I'm trying to extract the logic that filters and displays my mat-options for my mat-selects into their own component. For some reason however, the options get displayed but clicking on them doesn't fire an event.

The web app I'm writing have a lot of mat-selects which each potentially have a lot of mat-options. For obvious reasons, I need a way to filter the options so I'm using this node package. This pattern of "select with search field" appears a lot throughout the application, which is why I want to extract it into a component.

If all the code is contained in the same component, it works fine. The structure of this would look like this:

<select>
  <option>
    <search>
  <option>
  ... more options

However, since I extract the search and option filtering into its own component, there's now a component between the select and its options like this:

<select>
  <component> // Notice extra component
    <option>
      <search>
    <option>
    ... more options

I've set up the simplest example I could think of for how I'm using the select: https://stackblitz.com/edit/select-option-generator

The example doesn't feature the search bar since that doesn't affect the behavior.

When you click on one of the first 3 options which are contained in the same component as the select, they get selected as expected. If you click on one of the last 3 options which are contained in the nested component inside the select, they get highlighted but don't get selected.

I'm trying to figure out why the options in the nested component don't get selected when they're clicked on.

Thanks in advance.

Juan
  • 198
  • 1
  • 14
  • I believe the issue is that the options are not being bound to the selector because they are wrapped in the extra component. If there's a way to bind the options to the selector I would imagine that would fix it - but that's well beyond my limited knowledge. – BobtheMagicMoose Jun 23 '19 at 14:13
  • https://stackoverflow.com/questions/69034614/angular-material-nested-select-from-service – Laura Díaz Sep 06 '21 at 17:14

2 Answers2

0

I faced the same problem. I had to render options as a tree and render component recursively.

And I implemented it using ng-template

<ng-container *ngFor="let item of items">
  <div *ngTemplateOutlet="optionsTree; context: {optionItem: item, isChild: false}"></div>
</ng-container>
<ng-template #optionsTree let-optionItem="optionItem" let-isChild="isChild">
  <mat-option [ngClass]="{'child-option': isChild}" [value]="optionItem.id">{{optionItem.name}}</mat-option>
  <ng-container *ngFor="let children of optionItem.children">
   <div *ngTemplateOutlet="optionsTree; context: {optionItem: children, isChild: true}"></div>
  </ng-container>
</ng-template>

I hope it will help you

NechiK
  • 341
  • 2
  • 11
0

I checked the stackblitz, and it can be solved by removing the component and just adding each of the object from the subscribe to the this.foods array.

  1. Delete the following line from app.component.html
<option-generator [dataSource]="animalDataSource"></option-generator>
  1. Delete the option-generator.component.ts file (this renders the package you added useless)

  2. Modify your app.component.ts

  ngOnInit() {
    // Emit values after a delay to prevent changedAfterCheck error.
    setTimeout(() =>  {
      this.animalDataSource.next(this.animals);
    });

    this.animalDataSource.subscribe(data=> {
      let animals: Option[];
      animals = data;
      animals.forEach(animal => { 
        this.foods.push(animal);
      });
    });
  }

Check the fork to your stackblitz

Ian Preglo
  • 421
  • 2
  • 10