概述
在表單的設計過程中,會有一些表單字段需要在已知的內容中進行選擇,這在html中會使用select組件來設計該表單字段。而在Material中,同樣有與之對應的 <mat-select>
組件。這種組件在選項內容較少的情況下使用非常方便,
能很好的引導用戶在表單中,輸入規範的內容:
但是在選項內容過多時,這種 <mat-select>
組件,對用戶來說,想要找到自己想要的選項就比較麻煩,需要一個個選項去對比,查找:
幸運的是,在Material中提供了 mat-autocomplete
,這個組件和我們以前在JQuery時代使用的select2類似。它支持用戶鍵盤輸入功能,並根據輸入內容在已有的數據集合中進行過濾,選項內容動態的顯示過濾後的結果。
MatAutocomplete
基本用法
html:
<form class="example-form">
<mat-form-field class="example-full-width">
<input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option of options" [value]="option">
{{option}} </mat-option>
</mat-autocomplete>
</mat-form-field></form>
TypeScript:
import {Component} from '@angular/core';import {FormControl} from '@angular/forms';/**
* @title Simple autocomplete
*/
@Component({
selector: 'autocomplete-simple-example',
templateUrl: 'autocomplete-simple-example.html',
styleUrls: ['autocomplete-simple-example.css'],
})export class AutocompleteSimpleExample {
myControl = new FormControl();
options: string[] = ['One', 'Two', 'Three'];
}
呈現的效果如下:
高級API
在簡單用法中,我們發現,選項內容爲字符串,選擇中的值和顯示的值爲相同的。但在實際的應用過程中,我們需要選中的值和顯示的內容是不同的。
displayWith
舉個例子,我們有個需要選擇企業的字段,要存儲到數據庫的值是企業的編碼,而在界面上顯示的需要是企業的名稱。
在這個例子中,我們有個企業的數據結構:
interface Company {
code: string;
name: string;
}
companies: Company[] = []; constructor() { this.companies.push({code: 'qiye-01', name: '企業01'}); this.companies.push({code: 'qiye-02', name: '企業02'}); this.companies.push({code: 'qiye-03', name: '企業03'}); this.companies.push({code: 'qiye-04', name: '企業04'});
}
<form class="example-form">
<mat-form-field class="example-full-width">
<input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option of companies" [value]="option">
{{option.name}} </mat-option>
</mat-autocomplete>
</mat-form-field></form>
在html中,我們將mat-option的顯示內容修改成name,如 {{option.name}}
。這樣我們的下拉選項中就會顯示企業的名稱:
但是如果我們選中其中一個選項,就會發現結果和我們想象的不一樣,選中後的結果顯示並不是我們想要的企業名稱
此時,我們就需要使用API中提供的
在MatAutocomplete的API: displayWith。文檔已經很明確的告訴我們 displayWith
需要我們傳入一個已定義的函數
@Input()
displayWith: ((value: any) => string) | null
其中的函數形參value指的是 <mat-option *ngFor="let option of companies" [value]="option">
中value對應的option,此處option就是一個我們後臺定義的Company。這樣我們的value就擁有code和name兩個屬性。
這樣我們就可以定義一個displayWith的函數:
displayFn(value: any): string { // value: Company
return value ? value.name : undefined;
}
同時修改html
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let option of companies" [value]="option">
{{option.name}} </mat-option></mat-autocomplete>
這樣就會顯示我們想要的結果
在這種方式下,我們的formControl得到的其實是一個company對象,要存儲code,需要在從company對象中獲取code屬性值。
那麼如果我們想在formControl中直接得到code呢?
擴展用法
通過分析,我們發現,formControl獲得值的內容,其實和中的value是一致的。
因此,我們可以做如下修改, 將value改成option.code
<form class="example-form">
<mat-form-field class="example-full-width">
<input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option of companies" [value]="option.code">
{{option.name}} </mat-option>
</mat-autocomplete>
</mat-form-field></form>
得到如下顯示結果:
發現顯示的是code值,那我們還可以使用displayWith函數,讓它顯示企業名稱嗎?
答案是可以的。不過我們就不能在使用上面定義的displayFn方法了。
此時我們需要重新定義一個更高級的方法:
displayWith() { return (value) => { if (value) { const arr = that.companies.filter(item => item.code === value); if (arr.length) { return arr[0].name;
}
} return undefined;
}
}
在html中的使用方法如下:
<form class="example-form">
<mat-form-field class="example-full-width">
<input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayWith()">
<mat-option *ngFor="let option of companies" [value]="option.code">
{{option.name}} </mat-option>
</mat-autocomplete>
</mat-form-field></form>
需要[displayWith]=”displayWithThis(this)” 這樣特殊的使用方法。
爲什麼同樣是用displayWith,不同的value中,實際寫法差異卻如此大呢?
這個和JS的This作用於有關。
在不是用匿名函數的情況下,如:
displayFn(value) { if (value) { const arr = this.companies.filter(item => item.code === value); if (arr.length) { return arr[0].name;
}
} return undefined;
}
此時,如果將displayFn直接設置到mat-autocomplete中,此時的this表示mat-autocomplete對象,這樣this.companies.filter就會拋出異常。
結論
在本文中,我們主要講了MatAutocomplete在實際開發過程中,在不同的業務場景中,同樣的組件我們用到的不同的實現方式。每一種語言都有它自己的特性,掌握了這些特性,會讓我們工作時更加得心應手。