wcs-select autocomplete : Proposition de feature de recherche (code fourni)

Notre client nous a demandé une feature de recherche dans les selects, car nous avons de nombreux select très volumineux. Je vous propose notre implémentation sous forme de directive angular, bien que je sois conscient qu'elle ne corresponde pas à l'implémentation WCS. Peut être cela peut vous être utile pour une prochaine feature.

import {
  Directive,
  ElementRef,
  OnDestroy,
  OnInit,
  Renderer2,
} from '@angular/core';
import { Subject, debounceTime, fromEvent, takeUntil, tap } from 'rxjs';

@Directive({
  selector: 'wcs-select[searchable]',
  standalone: true,
})

export class SelectSearchDirective implements OnInit, OnDestroy {
  option: any;
  input: any;
  children: any;
  destroy$: Subject<boolean> = new Subject<boolean>();

  constructor(private elem: ElementRef, private renderer: Renderer2) {
    this.children = this.elem.nativeElement.childNodes;
    this.option = this.renderer.createElement('wcs-select-option');
    this.option.setAttribute('id', 'searchOption');
    this.option.setAttribute('stop-propagation', '');
    this.input = this.renderer.createElement('wcs-input');
    this.input.setAttribute('icon', 'search');
    this.input.setAttribute('type', 'text');
    this.input.setAttribute('clear-input', '');
    this.input.setAttribute('placeholder', 'Rechercher');

    this.renderer.appendChild(this.option, this.input);
    this.elem.nativeElement.appendChild(this.option);
  }
  ngOnInit(): void {
    this.renderer.listen(this.option, 'wcsSelectOptionClick', (e) => {
      e.stopImmediatePropagation();
    });

    const source = fromEvent(this.input, 'wcsInput');
    source
      .pipe(
        takeUntil(this.destroy$),
        debounceTime(450),
        tap((e: any) => {
          this.filterOptions(e.target.value);
        })
      )
      .subscribe();

    const sourceChange = fromEvent(this.input, 'wcsChange');
    sourceChange
      .pipe(
        takeUntil(this.destroy$),
        tap((e: any) => {
          e.stopPropagation();
        })
      ).subscribe();

  }

  ngOnDestroy(): void {
    this.destroy$.next(true);
    this.destroy$.unsubscribe();
  }

  filterOptions(e: string): void {
    if (e.length > 0) {
      const search = this.normalizeText(e);
      for (let i = 1; i < this.children.length; i++) {
        const node = this.children[i];
        const text = this.normalizeText(node.textContent as string);

        if (text.includes(search)) {
          node.hidden = false;
        } else {
          node.hidden = true;
        }
      }
    } else {
      for (let j = 1; j < this.children.length; j++) {
       this.children[j].hidden = false;
      }
    }
  }

  normalizeText(text: string): string {
    return text.normalize("NFD").replace(/\p{Diacritic}/gu, "").toUpperCase();
  }
}
Edited by Rémi Martinez