3
votes

I am using Angular material 2 multi select with Angular 5. I have added a search filter to it but when user searches for particular item and select those then it removes the items which was selected before.

I want to retain all the selected items unless and until the user deselect them.

Eg: I have a list of regions, if user selects Africa and Asia then searches and selects for Europe so we only see Europe as selected.

filterRegion.html

<mat-select [compareWith]="compareFn"  placeholder="REGION" [formControl]="region" multiple>
        <mat-select-trigger>
            {{region.value ? region.value[0]?.value : ''}}
            <span *ngIf="region.value?.length > 1" >
              (+{{region.value.length - 1}})
            </span>
          </mat-select-trigger>
        <mat-form-field class="searchBox">
            <input matInput placeholder="Search" [(ngModel)]="searchRegion" >
        </mat-form-field>
      <mat-option *ngFor="let r of regionList | filterSearch: searchRegion" [value]="r">{{r.value}}</mat-option>
    </mat-select>

filter-search-pipe.ts

    import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'filterSearch'
})
export class FilterSearchPipe implements PipeTransform {

  transform(value: any, input: string): any {
    if (input) {
      input = input.toLowerCase();
      return value.filter(function (el: Object) {
          return el['value'].toLowerCase().indexOf(input) > -1;
      })
    }
  return value;
  }

  }

I tried using this : https://github.com/albyrock87/material2/blob/5c196ad65d1bd5d8cb02a6bd78407ee2ef5be198/src/demo-app/select/select-demo.html

But i was getting error for mat-select-header and mat-select-search.

2

2 Answers

1
votes

for this problem i suggest you to use autoComplete module of angular-material.

<mat-form-field>
   <input type="text" matInput [formControl]="myControl" [matAutocomplete]="auto">
</mat-form-field>

<mat-autocomplete #auto="matAutocomplete">
   <mat-option *ngFor="let option of options" [value]="option">
      {{ option }}
   </mat-option>
</mat-autocomplete>

then for multiSelecting must use an chips container (a material module)

<mat-form-field class="demo-chip-list">
  <mat-chip-list #chipList>
    <mat-chip *ngFor="let fruit of fruits" [selectable]="selectable"
             [removable]="removable" (remove)="remove(fruit)">
      {{fruit.name}}
      <mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
    </mat-chip>
    <input placeholder="New fruit..."
           [matChipInputFor]="chipList"
           [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
           [matChipInputAddOnBlur]="addOnBlur"
           (matChipInputTokenEnd)="add($event)" />
  </mat-chip-list>
</mat-form-field>

and in the ts file of component. place:

import {Component} from '@angular/core';
import {MatChipInputEvent} from '@angular/material';
import {ENTER, COMMA} from '@angular/cdk/keycodes';

/**
 * @title Chips with input
 */
@Component({
  selector: 'chips-input-example',
  templateUrl: 'chips-input-example.html',
  styleUrls: ['chips-input-example.css']
})
export class ChipsInputExample {
  visible: boolean = true;
  selectable: boolean = true;
  removable: boolean = true;
  addOnBlur: boolean = true;

  // Enter, comma
  separatorKeysCodes = [ENTER, COMMA];

  fruits = [
    { name: 'Lemon' },
    { name: 'Lime' },
    { name: 'Apple' },
  ];


  add(event: MatChipInputEvent): void {
    let input = event.input;
    let value = event.value;

    // Add our fruit
    if ((value || '').trim()) {
      this.fruits.push({ name: value.trim() });
    }

    // Reset the input value
    if (input) {
      input.value = '';
    }
  }

  remove(fruit: any): void {
    let index = this.fruits.indexOf(fruit);

    if (index >= 0) {
      this.fruits.splice(index, 1);
    }
  }
}

therfore you must merge autoComplete and chip container. it become a very good UX.

-1
votes

One way I handled the same issue was just hiding elements from the DOM

mat-option [ngClass]="{hidden: isRegionFilteredOut(region)}"

.hidden {
  display:none
}