Ionic 4 显示加载、无记录和数据块的正确方式
[英] Ionic 4 Correct way to show Loading, No records and data block
本文介绍了Ionic 4 显示加载、无记录和数据块的正确方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
问题来了.我的应用程序中几乎所有页面都有三种状态.1.加载(我想在页面中显示微调器,为此我已经创建了一个组件)2. 没有找到记录(页面中央有一张图片,我也有一个组件)3. 数据加载和我的实际内容没有任何包装可能会弄乱设计.
这就是我目前这样做的方式,但在每个页面上看起来都不是很好.
<app-spinner *ngIf="!data; else page_content"></app-spinner><ng-template #page_content><ng-container *ngIf="data.length; else no_record">我的内容在这里</ng-容器></ng-模板><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>
有没有其他方法可以实现相同的功能,但代码看起来更漂亮.谢谢
解决方案
广告:这是 Angular 中的一个响应(我想可以为 Ionic 提供灵感)
你可以创建一个操作符,见这个 SO
好吧,将操作符更改为开始加载时发送1,如果没有数据finalize,则为-1,如果有数据finalize,则为0:
操作员:
export const prepare = (callback: () => void) =>{返回(来源:Observable):Observable=>延迟(() => {打回来();返回源;});};export const 表示 = <T>(指示符:Subject<any>)=>{让活着=真;让 noData=false;返回(来源:Observable):Observable=>源.管道(准备(() =>计时器(500).管道(takeWhile(() =>活着),拿(1)).subscribe(() => {指标.next(1);})),点击(res => {noData=(!res || (Array.isArray(res) && res.length<=0))}),完成(() => {活着=假;indicator.next(noData?-1:0);}));};export const toClass = (ClassType: { new(): T }) =>(来源:Observable) =>source.pipe(map(val => Object.assign(new ClassType(), val)));
加载组件:
@Component({选择器:'应用加载',模板:`<div *ngIf="dataService.loading$ | 异步作为响应"><div class="modal" (click)="dataService.loading$.next(0)"><div class="modal-content"><p *ngIf="response==1">正在加载...</p><p *ngIf="response==-1">Empty</p>
`,styleUrls: [ './loading.component.css' ]})导出类 LoadingComponent {构造函数(公共数据服务:数据服务){}}
看看如何使用 dataService.loading$.next(0)
关闭模态,以及我如何在构造函数中将我的 dataService 声明为 public
我举个简单的例子
load <div>{{数据}}
<app-loading></app-loading>
还有一个模拟调用的简单服务,返回随机空值或日期时间
导出类数据服务{loading$ = new Subject()getData():Observable{const observable=of(Math.random()<.5?'+new Date() 处的新数据:空值).管道(延迟(1000))返回 observable.pipe(表明(this.loading$))}}
您可以看到stackblitz , 您会看到正在加载",然后,有时您会看到它是空的,而另一次则是正在加载"关闭.
Here's the problem. I have three states of almost all the pages in my app.
1. Loading (where I want to show spinner within the page and for that I have created a component already)
2. No Records Found ( An image in center of the page and I have a component for this as well )
3. Data loading and my actual content without any wrapper around that which can mess up the design.
Thats how I am doing this currently which doesnt look great on every page.
<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>
Another way I can do is this but I dont want to repeat my checks again and again.
<app-spinner *ngIf="!data;"></app-spinner>
<app-no-record *ngIf="data && !data.length;"></app-no-record>
<ng-container *ngIf="data && data.length"></ng-container>
Is there any other way I can achieve this same functionality but with better looking code. Thanks
解决方案
Advertisement: This is a response in Angular (I suppose can be inspiration for Ionic)
You can create an operator, see this SO
Well, change the operator to send 1 when start loading, -1 if finalize without no data and 0 if finalize with data:
The operator:
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)));
the loading component:
@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){}
}
See how close the modal using dataService.loading$.next(0)
and how I declared as public my dataService in the constructor
I make a simple example of use
<button (click)="loadData()">load</button>
<div>
{{data}}
</div>
<app-loading></app-loading>
And a simple service that simulate a call, return random null or the date time
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$))
}
}
You can see the stackblitz , You see the "loading", then, some times you'll see that is empty, and another time the "loading" close.
这篇关于Ionic 4 显示加载、无记录和数据块的正确方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!