ng_dev
ng_dev

Reputation: 155

mat chip list inside a dialog window in Angular?

enter image description here

Then when user types in some data, the related dessert list data fetched from DB should be displayed in pre-populated mat-chips list format as follows:(may be if this is not possible, we can display a dropdown of prepopulated available desserts list from db so that user can select from those), but already selected value(duplicate) should not appear in the dropdown or by typing to the user to select again, both when the dialog is still open or closed and opened again. Because selected dessert should be unique as this chip data chosen will be stored in another table in database.

enter image description here

where user can delete or add whatever the chip he wants only from the available displayed chip list items and then click on submit. But the condition here should be like, as soon as a chip item is selected(not closing the item makes it selected for submission), duplicate chip item should not be chosen by typing again or after previous submission, which means: for example if I have 5chip items pre-populated as shown in image, the user should not be able to type a new chip item and submit, and also if chip4 and chip5 are selected and chip1,chip2,chip3 are closed(deleted) from the shown list, then only 1 chip4 & 1 chip5 with no duplicacy should be passed on submit to the page where this dialog was invoked on a button click event. Again when the user opens this dialog, the previously selected chip 4 & 5 should not appear again in the modal chip list.

I have tried implementing the autocomplete variety of mat chip list exactly as mentioned in Angular Material documentation like below, but that opens up a dropdown and not acc.to the needed format.

desserts.component.html:

    <div mat-dialog-content>
  <form>
    <div>
        <mat-form-field appearance="outline">
            <mat-label>Dessert*</mat-label>
            <mat-chip-list multiple #chipList>
              <mat-chip
                *ngFor="let dessert of desserts"
                [selectable]="selectable"
                [removable]="removable"
                (removed)="remove(dessert)">
                {{dessert}}
                <mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
              </mat-chip>
              <input
                placeholder="Dessert Name"
                #dessertInput
                [formControl]="dessertListCtrl"
                [matAutocomplete]="auto"
                [matChipInputFor]="chipList"
                [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
                [matChipInputAddOnBlur]="addOnBlur"
                (matChipInputTokenEnd)="add($event)">
            </mat-chip-list>
            <mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
              <mat-option *ngFor="let dessert of filteredDesserts | async" [value]="dessert">
                {{dessert}}
              </mat-option>
            </mat-autocomplete>
        </mat-form-field>
        <button mat-button (click)="onSubmit()">Submit</button>
      </div>
      </form>
</div>

desserts.component.ts:

export class DessertsComponent{
    
    selectable = true;
    removable = true;
    addOnBlur = true;
    separatorKeysCodes: number[] = [ENTER, COMMA];
    dessertListCtrl = new FormControl();
    filteredDesserts: Observable<string[]>;
    desserts: string[] = [];
    dessertsList: any = [];
    
    @ViewChild('dessertInput',{static: false}) dessertInput: ElementRef<HTMLInputElement>;
    @ViewChild('auto',{static: false}) matAutocomplete: MatAutocomplete;
  
    constructor(
                  private dbService: DBService,
                  public dialogRef: MatDialogRef<DessertsComponent>,
                  @Inject(MAT_DIALOG_DATA) public data: any,
               ) {
                    
                    this.dessertsListData();
                    this.filteredDesserts = this.dessertListCtrl.valueChanges.pipe(
                        startWith(null),
                        map((dessert: string | null) => dessert ? this._filter(dessert) : this.dessertsList.slice()));
                 }  
    dessertsListData(){
      this.dbService.dessertsListData().subscribe(
        (response: any) => {
          this.dessertsList = response;
        });
    }
    add(event: MatChipInputEvent): void {
      if (!this.matAutocomplete.isOpen) {
        const input = event.input;
        const value = event.value;
        
        if ((value || '').trim()) {
            this.desserts.push(value.trim());
        }
        
        if (input) {
          input.value = '';
        }
  
        this.dessertListCtrl.setValue(null);
      }
    }
  
    remove(dessert: string): void {
      const index = this.desserts.indexOf(dessert);
  
      if (index >= 0) {
        this.desserts.splice(index, 1);
      }
    }
    
    selected(event: MatAutocompleteSelectedEvent): void {
      this.desserts.push(event.option.viewValue);
      this.dessertInput.nativeElement.value = '';
      this.dessertListCtrl.setValue(null);
    }
  
    private _filter(value: string): string[] {
      const filterValue = value.toLowerCase();
      return this.dessertsList.filter(dessert => dessert.toLowerCase().indexOf(filterValue) === 0);
    }
    onSubmit(){
      this.dialogRef.close({data: this.desserts});
    }
  }

This dessert component is being invoked from another component this.dialog.open(DessertsComponent)

I am not an expert in Angular Material(v7), so would highly appreciate and thankful if any solution is provided for this issue.

Upvotes: 2

Views: 1131

Answers (0)

Related Questions