【发布时间】:2019-03-13 07:01:17
【问题描述】:
正如我过去所讨论的,我是编码新手,并试图自学 Angular - 也许这会带来新的职业!我正在为自己创建一个应用程序来掌握 Web 开发。我目前正在尝试在表单中使用材料自动完成功能,以便当用户向文本输入添加/插入值时,keyup 事件也会在一个可观察的对象中被监听,该可观察对象进行返回一些数据的 API 调用,我使用返回的日期填充自动完成(我的页面中有 3 个)。这是我的 HTML 表单...
<form novalidate [formGroup]="assignmentForm">
<div>
<input type="text" matInput placeholder="User" formControlName="worker" name="worker" [matAutocomplete]="workerTemplate" #worker>
<mat-autocomplete #workerTemplate="matAutocomplete">
<mat-option *ngFor="let worker of workerTags" [value]="worker">{{ worker.displayName}}</mat-option>
</mat-autocomplete>
</div>
<div>
<input type="text" matInput placeholder="Company" formControlName="company" name="company" [matAutocomplete]="companyTemplate" #company>
<mat-autocomplete #companyTemplate="matAutocomplete">
<mat-option *ngFor="let company of companyTags" [value]="company">{{company.displayName}}</mat-option>
</mat-autocomplete>
</div>
<div>
<input type="text" matInput placeholder="Department" formControlName="department" name="department" [matAutocomplete]="departmentTemplate" #department>
<mat-autocomplete #departmentTemplate="matAutocomplete">
<mat-option *ngFor="let department of departmentTags" [value]="department">{{department.displayName}}</mat-option>
</mat-autocomplete>
</div>
</form>
现在在我的组件中,我使用 Observable.merge 来监听所有三个输入,我去抖动以便用户不会使系统过载,我调用我的 API,然后在填充相关数据数组之前执行一些格式化逻辑自动完成。这是我的组件代码(为了便于阅读,我已经减少了这个)
public companyTags: any[];
public departmentTags: any[];
public workerTags: any[];
@ViewChild('company')
private companyEl: ElementRef;
@ViewChild('department')
private departmentEl: ElementRef;
@ViewChild('worker')
private workerEl: ElementRef;
private assignmentSubscription: Subscription;
constructor(private apiService: ApiService) {}
public ngOnInit() {
const companySource = fromEvent(this.companyEl.nativeElement, 'keyup');
const departmentSource = fromEvent(this.departmentEl.nativeElement, 'keyup');
const workerSource = fromEvent(this.workerEl.nativeElement, 'keyup');
const tagsSource = merge(companySource, departmentSource, workerSource)
.pipe(
debounceTime(500),
distinctUntilChanged(),
flatMap((ev: KeyboardEvent) => {
// if the user presses backspace the value is "" and all results are returned (to set limit)
if ((<HTMLInputElement>ev.target).value !== '') {
return this.apiService.getTags((<HTMLInputElement>ev.target).name, (<HTMLInputElement>ev.target).value, 3)
}
return of([]);
}),
);
this.assignmentSubscription = tagsSource.subscribe((res) => {
this.clearAllTags();
if (res.length > 0) {
// the type is contained in the array so we can determine which array we need to populate
// we can use interpolation rather than a horrible if then else
this[`${res[0].type}Tags`] = res;
}
});
}
public clearAllTags(): void {
this.companyTags = null;
this.departmentTags = null;
this.workerTags = null;
}
这一切都会奏效,但我想知道这是否是最有效的方法?我已经阅读了 flatMap、mergeMaop 和 concatMap,但我不确定哪种方法最适合我的情况?我是否应该将 flatMap 中包含的逻辑放在其他地方,因为它似乎是错误的地方?我不确定我什至会如何使用链接或向管道添加另一种方法来做到这一点(.do?)。任何建议和想法将不胜感激。如果我没有任何意义或我的问题措辞很糟糕,请说明,我将重写/编辑。非常感谢。
【问题讨论】: