Directive cant bind to MatSelect with ContentChild

Discussão em 'Angular' iniciado por marc, Fevereiro 7, 2025.

  1. marc

    marc Guest

    I'm having trouble with a directive that worked in Angular 8 but isn't binding to MatSelect in Angular 16. The directive is created, but @ContentChild never succeeds in binding to MatSelect.

    Directive Code

    import { Directive, AfterViewInit, ContentChild, ElementRef, Renderer2,
    ChangeDetectorRef } from '@angular/core';
    import { MatSelect } from '@angular/material/select';

    @Directive({
    standalone: false,
    selector: '[appMatSelectSearch]',
    })
    export class MatSelectSearchDirective implements AfterViewInit {

    private searchTimeout: any;
    private searchText = '';

    @ContentChild(MatSelect, { static: true }) matSelect!: MatSelect;

    constructor(private el: ElementRef, private renderer: Renderer2, private cdr:
    ChangeDetectorRef) {
    console.log('MatSelectSearchDirective initialized');
    }

    ngAfterViewInit(): void {
    this.cdr.detectChanges(); // Ensure change detection is run
    console.log('MatSelect:', this.matSelect);
    if (this.matSelect) {
    this.matSelect.openedChange.subscribe((opened) => {
    if (opened) {
    this.filterOptions();
    }
    });
    } else {
    console.error('MatSelect component not found');
    }
    }

    @HostListener('keydown', ['$event'])
    onKeydown(event: KeyboardEvent) {
    clearTimeout(this.searchTimeout);
    this.searchText += event.key.toLowerCase();
    this.filterOptions();
    this.searchTimeout = setTimeout(() => {
    this.searchText = '';
    }, 500); // Clear the search text after 500ms of inactivity
    }

    private filterOptions() {
    const options = this.matSelect.options.toArray();
    options.forEach((option) => {
    const text = option.viewValue.toLowerCase();
    this.renderer.setStyle(option._getHostElement(), 'display',
    text.includes(this.searchText) ? 'block' : 'none');
    });
    }
    }

    HTML Usage
    <div class="form-group">
    <mat-select appMatSelectSearch class="form-control">
    <mat-option *ngFor="let val of ['Option 1', 'Option 2', 'Option 3']" [value]="val">
    {{ val }}</mat-option>
    </mat-select>
    </div>


    Logs


    MatSelectSearchDirective initialized mat-select-search.directive.ts:29 MatSelect: undefined mat-select-search.directive.ts:37 MatSelect component not found core.mjs:10614 ERROR TypeError: Cannot read properties of undefined (reading 'options') at d.filterOptions (mat-select-search.directive.ts:53:36) at d.onKeydown (mat-select-search.directive.ts:46:10) at mat-select-search.directive.ts:16:14
    ​

    Issue

    • MatSelect works in the UI
    • The directive is created.
    • @ContentChild never binds to MatSelect.
    • This setup worked in Angular 8 but fails in Angular 16.

    Any insights on why @ContentChild isn't binding and how to resolve this would be greatly appreciated!

    Continue reading...

Compartilhe esta Página