Angular Материал, индикатор загрузки автозаполнения и отображение текста (результатов не найдено) - PullRequest
1 голос
/ 12 февраля 2020

Мне нужно показать загрузку при поиске данных, а также показать текст, когда запись не найдена.

У меня есть следующий 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?

моя вторая проблема - как показать сообщение о регистрации, не найденное, когда сервер возвращает пустой массив, потому что я работаю с asyn c.

1 Ответ

0 голосов
/ 13 февраля 2020

Однажды я сделал что-то похожее на это, и я попытался адаптировать его к тому, что вам нужно, так что здесь.

Начиная с сервиса, нам нужно настроить поток загрузки для просмотра .

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

...