Однажды я сделал что-то похожее на это, и я попытался адаптировать его к тому, что вам нужно, так что здесь.
Начиная с сервиса, нам нужно настроить поток загрузки для просмотра .
// 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, чтобы все знали, что он загружается, а затем все знают, что мы закончили на карте () , Это решает половину борьбы.
Далее, 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