angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.37k stars 6.75k forks source link

Angular Material, Autocomplete loading indicator and showing text (no results found) #18478

Open GlauberF opened 4 years ago

GlauberF commented 4 years ago

Feature Description

I need to show loading when searching for data and also show text when no record is found. I have the following html excerpt:

<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 code:

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))
        );
    }

for loading, I would control it with the tap() method, but my problem is how to know that the request inside switchMap(term => this.to.filter(term)) was finished, so I set the loading variable to false?

my second problem is how to show a registration message not found, when the server returns an empty array, because I am working with async.

crisbeto commented 4 years ago

Baking this into the autocomplete may be too opinionated since different apps have different ways of showing loading. We should have an example showing how to do it though.

GlauberF commented 4 years ago

in my use case, this is my implementation and it works perfectly.

https://stackblitz.com/edit/angular-autocomplete-dinamico?file=src%2Fapp%2Fautocomplete-type.component.ts

alcaidio commented 1 year ago

I see that there is still a "help wanted" label, is this still the case? Is there a feature to do? Or is it just finding a solution to your use case without modifying Material/autocomplete?

@GlauberF for "how to know that the request inside switchMap(term => this.to.filter(term)) was finished" you can use finalize from rxjs.

For "how to show a registration message not found, when the server returns an empty array" you can do a secondary stream based on result$.

isNotFound$ = this.result$.pipe(map(res => !!res?.length))