【问题标题】:How do I implement autocomplete in a <mat-select> component?如何在 <mat-select> 组件中实现自动完成功能?
【发布时间】:2018-10-31 09:19:44
【问题描述】:

我想将自动完成功能与多选 mat-select 选择器结合起来,因为选项列表会很长。

我已经在 stackoverflow 上搜索了答案,最接近答案的是 implement a search filter for the <mat-select> component of angular material

但是这些示例是关于表格而不是 mat-select。

我的问题是,是否可以将自动完成功能添加到 mat-select。如果不能,我是否可以在列表中的每个项目前面包含复选框的自动完成功能?

谢谢

编辑:我发现 angular 的 primefaces 确实有一个多选列表,可让您搜索列表项。它还包括一个内置的全选按钮!你可以在这里找到它https://www.primefaces.org/primeng/#/multiselect

您可以使用npm install primeng --save 安装primefaces

【问题讨论】:

  • 但是你知道有角材料文档包含建议框的例子吗?
  • 你的意思是自动完成框?从来没有听说过建议箱。我不需要自动完成/建议框,我需要一个具有项目搜索功能的选择框。没有这样的例子
  • 但基本一样。
  • 我说的是多选选择框,它不一样。自动完成不附带每个项目的复选框

标签: angular angular-material angular-material2


【解决方案1】:

一种方法是在 mat-select 中添加一个手动过滤器,以便它具有自动完成功能。 找到下面给定解决方案的示例代码here

为过滤文本添加输入控制器

    public filterControl = new FormControl();

在 mat-select 中添加过滤文本字段

     <mat-select
        [id]="fieldId"
        [formControl]="custonDropdown"
        (selectionChange)="onSelectChange($event.value)"
        (closed)="onPanelClose()"
        multiple
        panelClass="custom-mat-select">
        <input matInput 
             [formControl]="filterControl" 
             type="text" 
             name="filter-options" 
             id="filter-options" 
             placeholder="Search">
        <mat-option *ngFor="let option of filteredOptions | async"
             [value]="option.value" 
             [ngClass]="{'hide': !option.show}">
            {{option.name | translate}}
        </mat-option>
    </mat-select>

现在为过滤器文本字段值更改添加事件侦听器

     this.filteredOptions = this.filterControl.valueChanges.pipe(
            startWith(''),
            map((value: string) => {
                this.optionItems
                    .forEach(option => {
                        option.show = option.name.toLocaleLowerCase().includes(value.toLowerCase());
                    });
                return this.optionItems;
            })
        );

还可以让整个列表在下一个下拉菜单中打开,清除面板关闭时的过滤器文本字段,如模板代码(closed)="onPanelClose()"中所述

 onPanelClose() {
    this.filterControl.setValue('');
}

Demo

【讨论】:

  • 很好,我们也可以只做一个keyup监听器而不是formcontrol。
  • 但是如何解决下拉菜单宽度问题?
  • @IgorZinchenko 你能再具体一点吗。
  • @JEWELJACOB 对不起,我做了那个问题)材料的错误!)比你!
【解决方案2】:

是的,您可以使用 PrimeNG 多选控件。唯一的问题是您是否担心主题。

还有另一个选项使用 ma​​t-select-autocomplet

如何安装:

npm install select-autocomplete --save

npm:https://www.npmjs.com/package/mat-select-autocomplete

演示:https://stackblitz.com/edit/mat-select-autocomplete

【讨论】:

    【解决方案3】:

    您可以使用MatAutocomplete 和一些技巧来实现自动完成多选。我很确定你不能用MatSelect 做到这一点,因为这不能让你控制输入元素。该技术有点奇怪,但效果很好。这个想法是管理控制器中的选择,并将每个mat-option 的“值”设置为相同的东西 - 您选择的选项。您还需要捕获单击以允许用户与列表交互(而不是在单击时立即关闭),当然还需要在 mat-option 项目中提供复选框。其他一些技巧也是必要的 - here is a quick and dirty example 显示了该做什么。

    HTML:

    <mat-form-field class="example-full-width">
        <input type="text" placeholder="Select Users" aria-label="Select Users" matInput [matAutocomplete]="auto" [formControl]="userControl">
        <mat-hint>Enter text to find users by name</mat-hint>
    </mat-form-field>
    
    <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
        <mat-option *ngFor="let user of filteredUsers | async" [value]="selectedUsers">
            <div (click)="optionClicked($event, user)">
                <mat-checkbox [checked]="user.selected" (change)="toggleSelection(user)" (click)="$event.stopPropagation()">
                    {{ user.firstname }} {{ user.lastname }}
                </mat-checkbox>
            </div>
        </mat-option>
    </mat-autocomplete>
    
    <br><br>
    
    <label>Selected Users:</label>
    <mat-list dense>
        <mat-list-item *ngIf="selectedUsers?.length === 0">(None)</mat-list-item>
        <mat-list-item *ngFor="let user of selectedUsers">
            {{ user.firstname }} {{ user.lastname }}
        </mat-list-item>
    </mat-list>
    

    TS:

    import { Component, OnInit, ViewChild } from '@angular/core';
    import { FormControl } from '@angular/forms';
    import { Observable } from 'rxjs';
    import { map, startWith } from 'rxjs/operators';
    
    export class User {
      constructor(public firstname: string, public lastname: string, public selected?: boolean) {
        if (selected === undefined) selected = false;
      }
    }
    
    /**
     * @title Multi-select autocomplete
     */
    @Component({
      selector: 'multiselect-autocomplete-example',
      templateUrl: 'multiselect-autocomplete-example.html',
      styleUrls: ['multiselect-autocomplete-example.css']
    })
    export class MultiselectAutocompleteExample implements OnInit {
    
      userControl = new FormControl();
    
      users = [
        new User('Misha', 'Arnold'),
        new User('Felix', 'Godines'),
        new User('Odessa', 'Thorton'),
        new User('Julianne', 'Gills'),
        new User('Virgil', 'Hommel'),
        new User('Justa', 'Betts'),
        new User('Keely', 'Millington'),
        new User('Blanca', 'Winzer'),
        new User('Alejandrina', 'Pallas'),
        new User('Rosy', 'Tippins'),
        new User('Winona', 'Kerrick'),
        new User('Reynaldo', 'Orchard'),
        new User('Shawn', 'Counce'),
        new User('Shemeka', 'Wittner'),
        new User('Sheila', 'Sak'),
        new User('Zola', 'Rodas'),
        new User('Dena', 'Heilman'),
        new User('Concepcion', 'Pickrell'),
        new User('Marylynn', 'Berthiaume'),
        new User('Howard', 'Lipton'),
        new User('Maxine', 'Amon'),
        new User('Iliana', 'Steck'),
        new User('Laverna', 'Cessna'),
        new User('Brittany', 'Rosch'),
        new User('Esteban', 'Ohlinger'),
        new User('Myron', 'Cotner'),
        new User('Geri', 'Donner'),
        new User('Minna', 'Ryckman'),
        new User('Yi', 'Grieco'),
        new User('Lloyd', 'Sneed'),
        new User('Marquis', 'Willmon'),
        new User('Lupita', 'Mattern'),
        new User('Fernande', 'Shirk'),
        new User('Eloise', 'Mccaffrey'),
        new User('Abram', 'Hatter'),
        new User('Karisa', 'Milera'),
        new User('Bailey', 'Eno'),
        new User('Juliane', 'Sinclair'),
        new User('Giselle', 'Labuda'),
        new User('Chelsie', 'Hy'),
        new User('Catina', 'Wohlers'),
        new User('Edris', 'Liberto'),
        new User('Harry', 'Dossett'),
        new User('Yasmin', 'Bohl'),
        new User('Cheyenne', 'Ostlund'),
        new User('Joannie', 'Greenley'),
        new User('Sherril', 'Colin'),
        new User('Mariann', 'Frasca'),
        new User('Sena', 'Henningsen'),
        new User('Cami', 'Ringo')
      ];
    
      selectedUsers: User[] = new Array<User>();
    
      filteredUsers: Observable<User[]>;
      lastFilter: string = '';
    
      ngOnInit() {
        this.filteredUsers = this.userControl.valueChanges.pipe(
          startWith<string | User[]>(''),
          map(value => typeof value === 'string' ? value : this.lastFilter),
          map(filter => this.filter(filter))
        );
      }
    
      filter(filter: string): User[] {
        this.lastFilter = filter;
        if (filter) {
          return this.users.filter(option => {
            return option.firstname.toLowerCase().indexOf(filter.toLowerCase()) >= 0
              || option.lastname.toLowerCase().indexOf(filter.toLowerCase()) >= 0;
          })
        } else {
          return this.users.slice();
        }
      }
    
      displayFn(value: User[] | string): string | undefined {
        let displayValue: string;
        if (Array.isArray(value)) {
          value.forEach((user, index) => {
            if (index === 0) {
              displayValue = user.firstname + ' ' + user.lastname;
            } else {
              displayValue += ', ' + user.firstname + ' ' + user.lastname;
            }
          });
        } else {
          displayValue = value;
        }
        return displayValue;
      }
    
      optionClicked(event: Event, user: User) {
        event.stopPropagation();
        this.toggleSelection(user);
      }
    
      toggleSelection(user: User) {
        user.selected = !user.selected;
        if (user.selected) {
          this.selectedUsers.push(user);
        } else {
          const i = this.selectedUsers.findIndex(value => value.firstname === user.firstname && value.lastname === user.lastname);
          this.selectedUsers.splice(i, 1);
        }
    
        this.userControl.setValue(this.selectedUsers);
      }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2012-08-04
      • 1970-01-01
      • 1970-01-01
      • 2012-06-09
      • 1970-01-01
      • 2022-08-15
      • 2010-09-09
      • 1970-01-01
      • 2023-03-23
      相关资源
      最近更新 更多