角材料,自动完成加载指示器并显示文本(未找到结果)

问题描述 投票:1回答:1

我在搜索数据时需要显示加载,在找不到记录时也要显示文本。

我有以下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?

我的第二个问题是,当服务器返回空数组时,由于我正在使用异步,因此如何显示未找到注册消息。

angular rxjs angular-material
1个回答
0
投票

我曾经做过类似的事情,并且我试图使它适应您的需求,所以在这里。

[从服务开始,我们需要设置一个加载流来观看。

// 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

© www.soinside.com 2019 - 2024. All rights reserved.