16

I'm trying to add to add a search filter in my select option list because there are many options and I think that without a search, it will not be easy for the user to find the option that he wants to select.

I hope you will understand me because I'm not good at English.

Here's my code (it's just a part of my table)

<ng-container *ngFor="let menaceProcessus of menaceProcessusTab">
    <tr>
         <td colspan="4" bgcolor="#f1f1f1"><b>{{menaceProcessus?.processus?.nom}}</b></td>
    </tr>
    <ng-container *ngFor="let actif of menaceProcessus?.actifs">
        <tr>
            <td [rowSpan]="actif?.menaces?.length+1">{{actif?.actif?.nom}}</td>
        </tr>
     <ng-container *ngFor="let mnVuln of actif?.menaces">
        <tr>
             <td>{{mnVuln?.vulnerabilite?.nom}}</td>
             <td>
                 <select class="form-control" 
                  (change)="mnVuln?.menaceActif?.menace.id = $event.target.value; 
                            updateMenaceProcessus()">
                      <option></option>
                      <option *ngFor="let menace of menaces" 
                          [value]="menace.id" 
                          [selected]="menace.id === mnVuln?.menaceActif?.menace.id">
                        {{menace.nom}}</option>
                  </select>
              </td>
              <td>
                 <input class="form-control" 
                    type="text" [value]="mnVuln?.menaceActif?.probabilite"> 
              </td>
          </tr>
      </ng-container>
    </ng-container>
 </ng-container>
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
PowerGirl
  • 314
  • 1
  • 3
  • 11

5 Answers5

12

If you want to filter in select option, you can use datalist control of HTML. If you use it, there is no need to do extra coding for filtering. It has built-in functionality for filtering.

HTML :

<input list="menace" name="menace">

<datalist id="menace">
     <option *ngFor="let menace of menaces">{{menace.nom}} </option>
</datalist>
Parth Dhankecha
  • 151
  • 2
  • 8
5

I think you can use ng-select: https://www.npmjs.com/package/@ng-select/ng-select for Yor Requirement

2

If you want to filter your array menaces by typing on the first letter, then it is possible to filter your array like this:

HTML:

<select class="form-control" 
     (change)="mnVuln?.menaceActif?.menace.id = $event.target.value; 
               updateMenaceProcessus();
               filterMenaces($event)">
    <option></option>
    <option *ngFor="let menace of menaces" 
        [value]="menace.id" 
        [selected]="menace.id === mnVuln?.menaceActif?.menace.id">
        {{menace.nom}}</option>
</select>

TypeScript:

origMenaces = [];

methodAPIToGetMenaces() {
   this.yourService()
       .subscribe(s=> {
           this.menaces = s;
           this.origMenaces = s;
       });
}

filterMenaces(str: string) {
    if (typeof str === 'string') {
        this.menaces = this.origMenaces.filter(a => a.toLowerCase()
                                             .startsWith(str.toLowerCase())); 
    }
}

UPDATE 1:

If you want to filter by input value:

HTML:

<input type="text"         
    (ngModelChange)="filterItem($event)" 
    [(ngModel)]="filterText">
    <br>
<select 
     #selectList
     [(ngModel)]="myDropDown" 
    (ngModelChange)="onChangeofOptions($event)">
    <option value="empty"></option>
    <option *ngFor="let item of items">         
        {{item}}
    </option>    
</select>
<p>items {{ items | json }}</p>

TypeScript:

import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular 4';
  myDropDown : string;
  items = ['one', 'two', 'three'];
  origItems = ['one', 'two', 'three'];
  @ViewChild('selectList', { static: false }) selectList: ElementRef;

  onChangeofOptions(newGov) {
     console.log(newGov);
  }

  filterItem(event){
      if(!event){
          this.items = this.origItems;
      } // when nothing has typed*/   
      if (typeof event === 'string') {
          console.log(event);
          this.items = this.origItems.filter(a => a.toLowerCase()
                                             .startsWith(event.toLowerCase())); 
      }
      console.log(this.items.length);
      this.selectList.nativeElement.size = this.items.length + 1 ;       
   }      
}

Please, see work example at stackblitz

StepUp
  • 36,391
  • 15
  • 88
  • 148
0

I couldn't find any easy way to do this for the select, but the autocomplete component seems to do something very close to what is desired. The only issue with it is, that it does not require the value to be one of the options. That's why I created the following directive:

// mat-autocomplete-force-select.directive.ts
import { Directive, Input } from '@angular/core';
import { AbstractControl, NG_VALIDATORS, ValidationErrors, Validator } from '@angular/forms';
import { MatAutocomplete } from '@angular/material/autocomplete';

@Directive({
  selector: '[matAutocomplete][appMatAutocompleteForceSelect]',
  providers: [
    {
      provide: NG_VALIDATORS,
      useExisting: MatAutocompleteForceSelectDirective,
      multi: true,
    }
  ]
})
export class MatAutocompleteForceSelectDirective implements Validator {
  @Input('matAutocomplete')
  matAutocomplete!: MatAutocomplete;

  validate(control: AbstractControl): ValidationErrors | null {
    if (this.matAutocomplete.options && !this.isOptionOfAutocomplete(control.value)) {
      return { 'notAnAutocompleteValue' : true }
    }

    return null;
  }

  private isOptionOfAutocomplete(value: string) {
    return this.matAutocomplete.options.find(option => option.value === value) !== undefined;
  }
}

After that, you can add the directive to the input of the autocomplete, and it will have an error of notAnAutocompleteValue if it's not that.

<input matInput type="text" appMatAutocompleteForceSelect [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete" >
  <!-- ... -->
</mat-autocomplete>

For anyone unfamiliar with the autocomplete component, https://material.angular.io/components/autocomplete/overview will be helpful.

Cheers :)

Elias
  • 3,592
  • 2
  • 19
  • 42
0
<input list="menace" name="menace">
<datalist id="menace">
 <option *ngFor="let menace of menaces">{{menace.nom}} </option>
</datalist>

This works fine and in the case of a form just add a form control name and the value can be picked. Answered by @ParthDhankecha

makwasi Crispus
  • 143
  • 1
  • 8