Иони c 4 Правильный способ показать Загрузка, Нет записей и блок данных - PullRequest
0 голосов
/ 20 марта 2020

Вот проблема. У меня есть три состояния почти всех страниц в моем приложении. 1. Загрузка (где я хочу показать спиннер на странице, и для этого я уже создал компонент) 2. Записи не найдены (изображение в центре страницы, и у меня также есть компонент для этого) 3. Загрузка данных и мой фактический контент без какой-либо обертки вокруг того, что может испортить дизайн.

Вот как я делаю это в настоящее время, что не очень хорошо выглядит на каждой странице.

<app-spinner *ngIf="!data; else page_content"></app-spinner>
<ng-template #page_content>
<ng-container *ngIf="data.length; else no_record">
My Content goes here
</ng-container>
</ng-template>
<ng-template #no_record><app-no-record></app-no-record></ng-template>

Другой способ, которым я могу сделать это, но я не хочу повторять мои проверки снова и снова.

<app-spinner *ngIf="!data;"></app-spinner>
<app-no-record *ngIf="data && !data.length;"></app-no-record>
<ng-container *ngIf="data && data.length"></ng-container>

Есть ли какой-то другой способ, которым я могу достичь этой же функциональности, но с более привлекательным кодом. Спасибо

1 Ответ

0 голосов
/ 20 марта 2020

Реклама: Это ответ в Angular (я полагаю, это может быть источником вдохновения для Иони c)

Вы можете создать оператора, см. это SO

Хорошо, измените оператор на отправку 1 при загрузке, -1 при завершении без данных и 0 при завершении с данными:

Оператор:

export const prepare = <T>(callback: () => void) => {
    return (source: Observable<T>): Observable<T> =>
        defer(() => {
            callback();
            return source;
        });
};

export const indicate = <T>(indicator: Subject<any>) => {
    let alive = true;
  let noData=false;
    return (source: Observable<T>): Observable<T> =>
        source.pipe(
            prepare(() =>
                timer(500)
                    .pipe(
                        takeWhile(() => alive),
                        take(1)
                    )
                    .subscribe(() => {
                        indicator.next(1);
                    })
            ),
      tap(res=>{
        noData=(!res || (Array.isArray(res) && res.length<=0))
      }),
            finalize(() => {
                alive = false;
                indicator.next(noData?-1:0);
            })
        );
};

export const toClass = <T>(ClassType: { new(): T }) => (
    source: Observable<T>
) => source.pipe(map(val => Object.assign(new ClassType(), val)));

компонент загрузки:

@Component({
  selector: 'app-loading',
  template:`
  <div *ngIf="dataService.loading$ | async as response">
    <div class="modal" (click)="dataService.loading$.next(0)">
        <div class="modal-content">
            <p *ngIf="response==1">Loading...</p>
            <p *ngIf="response==-1">Empty</p>
        </div>
    </div>
</div>
  `,
  styleUrls: [ './loading.component.css' ]
})
export class LoadingComponent  {
  constructor(public dataService:DataService){}
}

Посмотрите, как близко модальное использование dataService.loading$.next(0) и как я объявил как publi c мой dataService в конструкторе

Я приведу простой пример использования

<button (click)="loadData()">load</button>
<div>
    {{data}}
</div>
<app-loading></app-loading>

И простой сервис, который имитирует вызов, возвращает случайный ноль или дату и время

export class DataService {
  loading$ = new Subject<any>()
  getData():Observable<any>
  {
    const observable=of(Math.random()<.5?
              'New Data at '+new Date():
               null
    ).pipe(delay(1000))

    return observable.pipe(
      indicate(this.loading$))
  }
}

Вы можете видеть stackblitz , Вы видите "загрузку", затем, иногда вы видите, что пусто, а в другой раз «загрузка» закрывается.

...