我在搜索数据时需要显示加载,在找不到记录时也要显示文本。
我有以下html摘录:
<input
matInput
[matAutocomplete]="auto"
[formControl]="formControl"
[formlyAttributes]="field"
[placeholder]="to.placeholder"
[errorStateMatcher]="errorStateMatcher"
/>
<mat-icon class="arrow-autocomplete">arrow_drop_down</mat-icon>
<mat-autocomplete
#auto="matAutocomplete"
[displayWith]="displayFn.bind(this)">
<mat-option *ngIf="isLoading" class="is-loading">
<mat-spinner diameter="25"></mat-spinner>
</mat-option>
<ng-container *ngIf="!isLoading">
<mat-option *ngFor="let value of result$ | async" [value]="value">
<ng-container *ngFor="let ky of to.filterKeys; let index = index">
{{
index !== to.filterKeys.length - 1
? value[ky] + ' - '
: value[ky]
}}
</ng-container>
<ng-container *ngIf="!to.filterKeys">
{{ value }}
</ng-container>
</mat-option>
</ng-container>
</mat-autocomplete>
Component.ts代码:
ngOnInit(): void {
super.ngOnInit();
this._unsubscribeAll = new Subject();
this.isLoading = false;
this.result$ = this.formControl.valueChanges.pipe(
takeUntil(this._unsubscribeAll),
debounceTime(300),
startWith(''),
tap(() => {
this.isLoading = true
}),
switchMap(term => this.to.filter(term))
);
}
对于加载,我可以用tap()
方法控制它,但是我的问题是如何知道switchMap(term => this.to.filter(term))
内部的请求已完成,所以我将加载变量设置为false?
我的第二个问题是,当服务器返回空数组时,由于我正在使用异步,因此如何显示未找到注册消息。
我曾经做过类似的事情,并且我试图使它适应您的需求,所以在这里。
[从服务开始,我们需要设置一个加载流来观看。
// Loading stream
private readonly loading = new Subject<boolean>();
get loading$(): Observable<boolean> {
return this.loading;
}
constructor(private http: HttpClient) {}
get(q: string) {
return this.http.get<IResults>(URL + q).pipe(
// Set loading to true when request begins
tap(() => this.loading.next(true)),
// If we get to this point, we know we got the data,
// set loading to false, return only the items
map((res) => {
this.loading.next(false);
return res.items;
})
)
}
// Cleanup.
ngOnDestroy() {
this.loading.unsubscribe();
}
在此示例中,预期数据为
interface IResults {
total_count: number,
incomplete_results: boolean,
items: []
}
因此,我们使用tap来让每个人都知道它正在加载,然后让每个人都知道我们在map()中已经完成。这解决了一半的麻烦。
接下来,component.ts非常简单,我们只是在观察可观察对象。
// Form
searchForm = new FormGroup({
query: new FormControl('')
})
// Get loading stream from service
loading$: Observable<boolean> = this.gs.loading$;
// Deconstruct form to just take the query
// Search on changes
searchResults$ = this.searchForm.valueChanges.pipe(
switchMap(({query}) => this.gs.get(query))
);
constructor(private gs: GithubService) { }
现在我们可以在html中完成此操作。
<!-- ngIf so my http request is only called once-->
<form [formGroup]="searchForm"
*ngIf="{results: searchResults$ | async, loading: loading$ | async} as obs">
<!-- Search input -->
<mat-form-field appearance="legacy">
<input matInput [matAutocomplete]="autoComplete" formControlName="query">
<mat-icon matSuffix>arrow_drop_down</mat-icon>
<mat-hint>Search Github Users</mat-hint>
</mat-form-field>
<!-- Auto Complete -->
<mat-autocomplete #autoComplete="matAutocomplete">
<!-- If we're loading -->
<mat-option class="loading" *ngIf="obs.loading">
<mat-spinner diameter="35"></mat-spinner>
</mat-option>
<!-- If we're not loading AND the array length is 0, show this -->
<mat-option *ngIf="obs.results?.length === 0 && !obs.loading">
No user found
</mat-option>
<!-- Actual payload -->
<ng-container *ngIf="!obs.loading">
<mat-option *ngFor="let result of obs.results">
{{result.login}}
</mat-option>
</ng-container>
</mat-autocomplete>
</form>
我们将ngif放在表格中,以避免在同一组件中发出多个GET请求,并将其放入我们可以引用的对象中。将自动完成功能连接到输入。现在我们可以添加一对有条件的一对(数组的长度,如果正在加载)。
我还创建了一个堆栈闪电来测试这一切。很好玩!https://stackblitz.com/github/baxelson12/ng-mat-autocomplete