最近产品经理提了一个需求,想要一个有自动匹配输入框的弹窗,否则只有下拉框,添加用户的时候需要翻一百多个选项太痛苦了。
由于我使用的是一个动态弹窗,可以根据不同的场景进行DIY弹窗的内容和样式(例如input,select,checkebox等)所以我想把autoComplete也加进去,相当于新增一种可选择的组件。
但我发现autoComplete是必须使用一个带有默认字段的formControl,而弹窗则是使用一个form表单数组进行回传数据的,无法设置默认值。
所以我的思路是用一个单独的formControl进行取值,最后将选中的选项值放进form表单中回传数据。
并且还需要注意的是中间需要新加一些判断,防止已经调用弹窗的页面报错。
以下是实现代码:
html部分:
<div *ngIf="otherColumn" class="p-24 pb-0 m-0" fusePerfectScrollbar>
<ng-container *ngFor="let item of otherColumn">
<!-- 使用matAutocomplete前,请确保你传的数组是object数组且只有两个键:type(下拉框显示的文本)和value(下拉框选中的值) -->
<div *ngSwitchCase="'autoComplete'">
<mat-form-field appearance="outline">
<mat-label>{{ item.label }}</mat-label>
<input type="text" placeholder="" aria-label="" matInput [formControl]="autoCompleteResult"
[matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option">
{{ option.type }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
</ng-container>
</ng-container>
</div>
<div mat-dialog-content class="p-24 pb-0 m-0" fusePerfectScrollbar #DialogContent>
<form [formGroup]="formData">
<div *ngFor="let form of formColumn; let i=index" fxLayout="column" fxLayoutAlign="start start">
……
</div>
</form>
</div>
ts部分:
先定义需要的数组或者字段
formColumn: any[] = []; // 表单项
autoCompleteResult = new FormControl({ type: null, value: null }); // 自动匹配框选中的值
autoCompleteArray: any[] = []; // 用于接收下拉框数组
autoCompleteValue: any = ''; // 自动匹配框回传数据的键
创建form表单时提前设置对应的字段(没有字段的话无法将数据放进去)
/**
* 创建表单
* @returns {FormGroup}
*/
createNewForm(): FormGroup {
const formObj = {};
this.formColumn.forEach(item => {
formObj[item.value] = [this.formInit[item.value]];
});
// 创建表单时判断otherColumn是否为空(避免otherColumn为空时报错)
if (isNotNullOrUndefined(this.otherColumn)) {
// 循环otherColumn判断是否有autoComplete
this.otherColumn.forEach(index => {
if (index['type'] === 'autoComplete') {
// 如果有autoComplete,在创建表单的时候提前赋予一个键
formObj[index['value']] = [];
// 赋值给一个提前准备好的字段,避免后续回传弹窗数据的时候需要再进行一次forEach
this.autoCompleteValue = index['value'];
}
});
}
// 使表单的formControl值等于默认值defaults
this.formColumn.forEach((item, index, value) => {
// 判断defaults值是否为空,如果为空则不设置默认值
if (value[index].defaults !== null && value[index].defaults !== '' && value[index].defaults !== undefined) {
formObj[item.value] = [value[index].defaults];
}
});
return this._formBuilder.group(formObj);
}
在点击确定的时候,将对应的值放进form表单中再回传数据
// 传值:可通过afterClosed获取值
saveDialog(): void {
const form = this.formData.getRawValue();
const curSrc = this.curImageArr[0];
this.formColumn.forEach(item => {
if (item.type === 'time') {
// form[item.value] = moment(form[item.value]).format('YYYY-MM-DD'); // 时间格式化
form[item.value] = this.general.formatTimeToDate(form[item.value]);
} else if (item.detailType === 'file') {
if (curSrc) {
// 文件名 curSrc.title
form['file_name'] = curSrc.title;
form[item.value] = curSrc.src; // 上传的单个文件
}
}
});
const autoCompleteResultValue = this.autoCompleteResult.value;
// autoCompleteValue有赋值则说明otherColumn不为空且有autoComplete组件
if (isNotNullOrUndefined(this.otherColumn) && this.autoCompleteValue !== '') {
form[this.autoCompleteValue] = autoCompleteResultValue;
};
this.matDialogRef.close({ form });
}
最后就是一些其他部分的代码,构建autoComplete需要的数组等
ngOnInit(): void {
// 构建自动匹配框所用的数组
if (isNotNullOrUndefined(this.otherColumn)) {
this.otherColumn.forEach(index => {
if (index['type'] === 'autoComplete') {
this.autoCompleteArray = index['selectArr'];
this.getList(this.autoCompleteArray);
}
});
}
}
getList(List): void {
this.filteredOptions = this.autoCompleteResult.valueChanges.pipe(
startWith(''),
map(value => (typeof value === 'string' ? value : value.type)),
map(name => (name ? this._filter(name) : List.slice())),
);
}
private _filter(name: string): AutoArray[] {
const filterValue = name.toLowerCase();
return this.autoCompleteArray.filter(option => option.type.toLowerCase().includes(filterValue));
}
displayFn(array: AutoArray): string {
return array && array.type ? array.type : '';
}