简体   繁体   中英

Angular mat-chips with mat-autocomplete and input combined, adds an extra chip when selecting from list

I have combined mat-chips autocomplete and input (as both are present in the example section in the docs), but it creates a problem, when I type in part of an Autocomplete Option to filter the options, and then click it, it adds the input value plus the clicked item to the chip list. which is probably a very logcial thing for it to do, since i dont see any reason why it should ignore the blur event if the item was clicked, is there a built-in way / hack to work around this? here is my code:

<mat-form-field class="chip-list">
    <mat-chip-list #chipList aria-label="Op selection" class="mat-chip-list-stacked">
        <mat-basic-chip *ngFor="let sop of selectedOps" [selectable]="selectable" 
         [removable]="removable" (removed)="remove(sop)">
            <mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
            {{sop.val}}
        </mat-basic-chip>
    </mat-chip-list>
    <div style="position: relative;">
        <input matInput [formControl]="chipControl" aria-label="subcats" #SelectInput
            [matAutocomplete]="auto" [matChipInputFor]="chipList" 
           [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
            (matChipInputTokenEnd)="add($event)" [matChipInputAddOnBlur]="addOnBlur">
       
        <mat-icon class="icon" (click)="SelectInput.focus()">keyboard_arrow_down</mat-icon>
    </div>

    <mat-autocomplete #auto="matAutocomplete">
        <mat-option *ngFor="let op of filteredOps | async" [value]="op">

            <div (click)="optionClicked($event, op)">
                <mat-checkbox [checked]="op.selected" (change)="toggleSelection(op)"
                    (click)="$event.stopPropagation(); ">
                    {{ op.val }}
                </mat-checkbox>
            </div>

        </mat-option>

    </mat-autocomplete>
</mat-form-field>

was I doing something wrong? or is it not ment to work together in the first place? thanks for any feedback!

Here's a solution as posted @ https://github.com/angular/components/issues/19279#issuecomment-627263513

Quote from there:

We can emulate matChipInputAddOnBlur self.

I added (blur)=addOnBlur($event) to the input and disabled matChipInputAddOnBlur. Click on mat-input should be ignored.

my implementation:

 addOnBlur(event: FocusEvent) {
    const target: HTMLElement = event.relatedTarget as HTMLElement;
    if (!target || target.tagName !== 'MAT-OPTION') {
      const matChipEvent: MatChipInputEvent = {input: this.fruitInput.nativeElement, value : this.fruitInput.nativeElement.value};
      this.add(matChipEvent);
    }
  }

example https://stackblitz.com/edit/angular-rd38q1-jxbjjb?file=src%2Fapp%2Fchips-autocomplete-example.ts

I'll leave one more solution here.

The main problem is that blur on different browsers works a bit differently, so there listener for outside click, which ignore clicks on mat-option and on input :

constructor(private eRef: ElementRef, @Inject(DOCUMENT) private _document: Document) {
    this.listenOutsideClick();
  }

private listenOutsideClick(): void {
      fromEvent(this._document, 'click', { passive: false }).pipe(takeUntil(this.isDestroyed$))subscribe((event) => {
        const inside = this.eRef.nativeElement.contains(event.target);
        const clickOnOption = (event.target as HTMLElement).tagName === 'MAT-OPTION';

        if (clickOnOption || inside) {
          // clicked inside;
        } else {
          // clicked outside
          if (this.chipsInput.nativeElement.value) {
            this.add({ 
              input: this.chipsInput.nativeElement, 
              value: this.chipsInput.nativeElement.value 
             } as MatChipInputEvent
           );
           
          }
        }
      })
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM