Ionic 4:"Loading Controller" dismiss() 在 present() 之前被调用,这将保持微调器不被解散
Ionic 4: "Loading Controller" dismiss() is called before present() which will keep spinner without dismissing
我使用 "Ionic Loading Controller" 来显示微调器,直到检索到数据然后调用 "dismiss()" 将其关闭。
它工作正常,但有时当应用程序已经有数据时,"dismiss()" 在 "create()" 和 "present()" 完成之前被调用,这将保持微调器不被关闭...
我尝试调用"loadingController.present().then()"里面的数据,但是导致数据变慢了...
这是一个错误吗?
如何解决这个问题?
我的代码示例:
customer: any;
constructor(public loadingController: LoadingController, private customerService: CustomerService)
ngOnInit() {
this.presentLoading().then(a => consloe.log('presented'));
this.customerService.getCustomer('1')
.subscribe(customer => {
this.customer = customer;
this.loadingController.dismiss().then(a => console.log('dismissed'));
}
}
async presentLoading() {
const loading = await this.loadingController.create({
message: 'wait. . .',
duration: 5000
});
return await loading.present();
}
这就是我解决问题的方法..
我使用布尔变量 "isLoading" 在调用 dismiss() 时更改为 false。
在 present() 完成后,如果 "isLoading" === false (意味着 dismiss() 已经调用)那么它将立即关闭。
另外,我把代码写在一个服务里,这样我就不用在每个页面都重新写了。
loading.service.ts
import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Injectable({
providedIn: 'root'
})
export class LoadingService {
isLoading = false;
constructor(public loadingController: LoadingController) { }
async present() {
this.isLoading = true;
return await this.loadingController.create({
// duration: 5000,
}).then(a => {
a.present().then(() => {
console.log('presented');
if (!this.isLoading) {
a.dismiss().then(() => console.log('abort presenting'));
}
});
});
}
async dismiss() {
this.isLoading = false;
return await this.loadingController.dismiss().then(() => console.log('dismissed'));
}
}
然后只需从页面调用 present() 和 dismiss()。
相关示例:
customer: any;
constructor(public loading: LoadingService, private customerService: CustomerService)
ngOnInit() {
this.loading.present();
this.customerService.getCustomer('1')
.subscribe(
customer => {
this.customer = customer;
this.loading.dismiss();
},
error => {
console.log(error);
this.loading.dismiss();
}
);
或者,您必须像下面这样更改调用加载的代码
async ngOnInit() {
const loading = await this.loadingController.create();
await loading.present();
this.customerService.getCustomer('1')
.subscribe(customer => {
this.customer = customer;
loading.dismiss();
}
}
我正在使用类似的解决方案,但依赖于加载叠加层的 ID,并让离子加载控制器管理应该在顶部的叠加层。
加载服务
import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Injectable({
providedIn: 'root'
})
export class LoadingService {
constructor(public loadingController: LoadingController) { }
async present(loadingId: string, loadingMessage: string) {
const loading = await this.loadingController.create({
id: loadingId,
message: loadingMessage
});
return await loading.present();
}
async dismiss(loadingId: string) {
return await this.loadingController.dismiss(null, null, loadingId);
}
}
Components/Services 使用 LoadingService
import { LoadingService } from '../loading/loading.service';
@Injectable({
providedIn: 'root'
})
export class MessagesService {
...
constructor(
protected http: HttpClient,
protected loading: LoadingService
) { }
...
protected async loadMessagesOverview() {
const operationUrl = '/v1/messages/overview';
await this.loading.present('messagesService.loadMessagesOverview', 'Loading messages...');
this.http.get(environment.apiUrl + operationUrl)
.subscribe((data: Result) => {
...
this.loading.dismiss('messagesService.loadMessagesOverview');
}, error => {
...
this.loading.dismiss('messagesService.loadMessagesOverview');
console.log('Error getting messages', error);
});
}
}
对于 Ionic 4 检查此解决方案
来源Link
import { Component } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
loaderToShow: any;
constructor(
public loadingController: LoadingController
) {
}
showAutoHideLoader() {
this.loadingController.create({
message: 'This Loader Will Auto Hide in 2 Seconds',
duration: 20000
}).then((res) => {
res.present();
res.onDidDismiss().then((dis) => {
console.log('Loading dismissed! after 2 Seconds');
});
});
}
showLoader() {
this.loaderToShow = this.loadingController.create({
message: 'This Loader will Not AutoHide'
}).then((res) => {
res.present();
res.onDidDismiss().then((dis) => {
console.log('Loading dismissed! after 2 Seconds');
});
});
this.hideLoader();
}
hideLoader() {
setTimeout(() => {
this.loadingController.dismiss();
}, 4000);
}
}
我遇到了同样的问题,也许我有一个使用离子事件本身的更简单、更可靠的解决方案。这对我有用。它将等到创建加载程序,然后才完成服务调用,只有当服务调用完成时,才会关闭加载程序。希望对您有所帮助..
yourFuncWithLoaderAndServiceCall(){
this.presentLoading().then(()=>{
this.xyzService.getData(this.ipObj).subscribe(
res => {
this.dismissLoading();
this.dismissLoading().then(() => {
this.responseObj = res;
})
}
});
}
async presentLoading() {
this.loader = await this.loadingController.create({
translucent: true
});
await this.loader.present();
}
async dismissLoading() {
await this.loader.dismiss();
}
虽然公认的解决方案可以工作...我认为最好始终只加载 1 次。我的解决方案取消了以前的加载,如果它存在,并创建新的加载。我通常一次只想显示 1 个加载(我的特定用例),所以这个解决方案对我有用。
接受的解决方案提出了可能出现孤立加载的问题。但这是一个很好的起点。
因此,这是我建议的注射服务(如果需要,您可以使用更多的离子设置对其充电。我不需要它们,所以我没有添加more in the present function, 但可以相应添加):
import {Injectable} from '@angular/core';
import {LoadingController} from '@ionic/angular';
@Injectable({
providedIn: 'root'
})
export class LoadingService {
currentLoading = null;
constructor(public loadingController: LoadingController) {
}
async present(message: string = null, duration: number = null) {
// Dismiss previously created loading
if (this.currentLoading != null) {
this.currentLoading.dismiss();
}
this.currentLoading = await this.loadingController.create({
duration: duration,
message: message
});
return await this.currentLoading.present();
}
async dismiss() {
if (this.currentLoading != null) {
await this.loadingController.dismiss();
this.currentLoading = null;
}
return;
}
}
简单的方法是添加 setTimeOut 函数:
setTimeout(() => {
this.loading.dismiss();
}, 2000);
我遇到了同样的问题,显然我是通过首先确定问题来解决的。这个问题发生在加载器的持续时间过期时,所以它基本上在我们没有完全控制的情况下被解雇了。
现在,它将正常工作,直到您也使用 dismiss()
手动。
因此,如果您要手动使用 dismiss()
持续时间,请在创建时删除持续时间。然后使用 setTimeout()
或者
// create loader
this.loader = this.loadingCtrl.create()
// show loader
this.loader.present().then(() => {})
// add duration here
this.loaderTimeout = setTimeout(() => {
this.hideLoader()
}, 10000)
然后在此处创建隐藏装载程序
// prepare to hide loader manually
hideLoader() {
if (this.loader != null) {
this.loader.dismiss();
this.loader = null
}
// cancel any timeout of the current loader
if (this.loaderTimeout) {
clearTimeout(this.loaderTimeout)
this.loaderTimeout = null
}
}
此 onDidDismiss() 事件应在调用 .present() 函数后创建。
示例:
this.loader.present().then(() => {
this.loader.onDidDismiss(() => {
console.log('Dismiss');
})
});
同样的问题,这里是我的解决方案(ionic 4 和 angular 7):
从接受的解决方案开始。
礼物创造一次装货
在 dismiss 函数中,我仅在 dimiss returns true
时将 isShowing 设置为 false
import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Injectable({
providedIn: 'root'
})
export class LoadingService {
isDismissing: boolean;
isShowing: boolean;
constructor(public loadingController: LoadingController) {
}
async present() {
if(this.isShowing){
return
}
this.isShowing = true
await this.loadingController.create({spinner: "dots"}).then(re => {
re.present()
console.log("LoadingService presented", re.id)
})
}
async dismiss() {
if(this.isShowing){
await this.loadingController.dismiss().then(res => {
if(res){
this.isShowing = false
console.log("LoadingService dismissed", res);
}
})
}
}
}
以下是我在项目中解决相同问题的方法。我在 HTTP 拦截器中使用此服务来显示应用程序中所有 REST API 调用的加载器。
loading.service.ts
import {Injectable} from '@angular/core';
import {LoadingController} from '@ionic/angular';
@Injectable({
providedIn: 'root'
})
export class LoadingService {
constructor(public loadingController: LoadingController) {
}
async present(options: object) {
// Dismiss all pending loaders before creating the new one
await this.dismiss();
await this.loadingController
.create(options)
.then(res => {
res.present();
});
}
/**
* Dismiss all the pending loaders, if any
*/
async dismiss() {
while (await this.loadingController.getTop() !== undefined) {
await this.loadingController.dismiss();
}
}
}
在原来的问题上下文中,这可以像下面这样使用:
...
import {LoadingService} from '/path/to/loading.service';
...
customer: any;
constructor(public loadingService: LoadingService, private customerService: CustomerService)
ngOnInit() {
this.loadingService.present({
message: 'wait. . .',
duration: 5000
});
this.customerService.getCustomer('1')
.subscribe(customer => {
this.customer = customer;
this.loadingService.dismiss();
}
}
我知道这个问题是一年前问的。我面临同样的问题。我只想 post 我的解决方案。希望即将到来的访客能得到帮助。
async dismissLoading() {
console.log("dismiss");
this.isLoading = false;
}
private async presentLoading(msg) {
console.log("loading");
const loading = await this.loadingCtrl.create({
message: msg,
});
await loading.present();
var timer = setInterval(() => {
if (!this.isLoading) {
loading.dismiss();
clearInterval(timer);
console.log("set dismiss");
}
}, 1000);
}
async loadingmsg() {
this.isLoading = true;
await this.presentLoading("Please wait while...");
}
这个解决方案对我有用。如有不妥请指正
在尝试了一切之后,这就是我最终想出的办法。到目前为止似乎运作良好。
尝试使用间隔为 500 毫秒的 setInterval。我还尝试使函数保持非异步,以便在消费端可以轻松使用它。
import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Injectable({ providedIn: 'root' })
export class UiService {
constructor(private loading: LoadingController) { }
private loader: HTMLIonLoadingElement;
private loaderLoading = false;
public showLoading(message: string) {
this.loaderLoading = true;
this.loading.create({
message,
showBackdrop: true
}).then(load => {
this.loader = load;
load.present().then(() => { this.loaderLoading = false; });
});
}
public dismissLoading() {
const interval = setInterval(() => {
if (this.loader || !this.loaderLoading) {
this.loader.dismiss().then(() => { this.loader = null; clearInterval(interval)});
} else if (!this.loader && !this.loaderLoading) {
clearInterval(interval);
}
}, 500);
}
}
使用列表对我来说效果更好
import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Injectable({providedIn: 'root'})
export class LoadingService {
private loaders = new Array<HTMLIonLoadingElement>();
constructor(public loadingController: LoadingController) { }
present(options?: object) {
if (this.loaders.length === 0) {
this.loadingController.create(options).then(loader => {
this.loaders.push(loader);
loader.present();
});
}
}
async dismiss() {
if (this.loaders && this.loaders.length > 0) {
this.loaders.forEach(async loader => {
await loader.dismiss()
.then(() => {
loader = null;
})
.catch(e => console.log(e))
.finally(() => this.loaders = new Array<HTMLIonLoadingElement>());
});
}
}
}
我在使用 Ionic 4 加载控制器时遇到了同样的问题。
经过反复试验,我找到了可行的解决方案。
因为加载控制器函数正在使用 async 和 await,因为它们都是异步函数。
dismiss() 函数将在 present() 函数之前调用,因为 dismiss 函数不会等到创建和呈现加载程序,它会在 present() 函数调用之前触发。
下面是工作代码,
loading:HTMLIonLoadingElement;
constructor(public loadingController: LoadingController){}
presentLoading() {
if (this.loading) {
this.loading.dismiss();
}
return new Promise((resolve)=>{
resolve(this.loadingController.create({
message: 'Please wait...'
}));
})
}
async dismissLoading(): Promise<void> {
if (this.loading) {
this.loading.dismiss();
}
}
someFunction(){
this.presentLoading().then((loadRes:any)=>{
this.loading = loadRes
this.loading.present()
someTask(api call).then((res:any)=>{
this.dismissLoading();
})
})
}
通过这种方式,它还解决了并发 API 调用加载器解除问题的修复。
您也可以调用这些函数来形成拦截器。没有固定的持续时间,因为如果任何调用需要很多时间,加载程序将继续。但是,如果有人给出持续时间,那么如果 API 不会在此时停止,加载程序将停止
import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Injectable({
providedIn: 'root'
})
export class LoadingService {
isLoading = false;
loaderCounter = 0;
loading: HTMLIonLoadingElement;
constructor(public loadingController: LoadingController) {}
async present() {
this.loaderCounter = this.loaderCounter + 1;
if (this.loaderCounter === 1) {
this.isLoading = true;
const { loadingDuration, loadingMessage = loadingDefaultOptions.loadingMessage, loadingCssClass } = options;
this.loading = await this.loadingController.create({
duration: loadingDuration,
message: loadingMessage,
cssClass: loadingCssClass
});
await this.loading.present();
}
}
async dismiss() {
this.loaderCounter = this.loaderCounter - 1;
if (this.loaderCounter === 0) {
this.isLoading = false;
await this.loading.dismiss();
}
}
}
我找到了一种新方法来做到这一点。我希望它有所帮助!
它使用的是加载的id。所以如果你有很多加载,你不想忽略错误的加载。
服务中:
async showLoading(loadingId: string, loadingMessage: string = 'Loading...') {
const loading = await this.loadingCtrl.create({
id: loadingId,
message: loadingMessage,
spinner: 'circles'
});
return await loading.present();
}
async dismissLoader(loadingId: string) {
return await this.loadingCtrl.dismiss(null, null, loadingId).then(() => console.log('loading dismissed'));
}
在调用加载的组件中:
await this.globalVars.showLoading('ifOfLoading')
正在关闭加载:
this.globalVars.dismissLoader('ifOfLoading')
我对这个问题的解决方案是设置一个状态变量。这是:
@Injectable()
export class LoaderSerive {
private status: 'pending' | 'dismissed' | 'present' = 'dismissed';
constructor(public loadingCtrl: LoadingController) {}
public show() {
if (this.status === 'present') {
this.hide();
}
this.status = 'pending';
this.loadingCtrl.create({
id: 'spoon-indicator-1',
spinner: null,
message: `
<div>
<div class="loading-indicator--position">
<div class="loading-indicator">
<div class="bowl">
<div class="spoon"></div>
<div class="bowl-content"></div>
</div>
</div>
</div>
</div>`,
duration: 6000
})
.then((loader) => loader.present())
.then(() => {
if (this.status === 'pending') {
this.status = 'present';
} else {
this.hide();
}
});
}
public hide() {
this.loadingCtrl
.dismiss(null, undefined, 'spoon-indicator-1')
.catch((err) => Utilities.log('Loader error!', err))
.then(() => this.status = 'dismissed');
}
}
离子 5 -
简单而简短,使用 setTimeout,setInterval 与其说是解决方案,不如说是一种变通方法。
在我的例子中,我有 presentLoading 方法异步和 dismissLoading 方法同步..导致这个问题。
我刚刚将 async await 添加到我的 dismissoading 中,它工作得很好。对于没有“覆盖不存在”错误的安全开关,添加了一个布尔值,仅在加载程序存在时才关闭
async presentLoading() {
this.loadingPresent = true;
const loading = await this.loadingController.create({
message: 'Loading...',
});
return await loading.present();
}
async dismissLoading() {
if (this.loadingPresent) {
await this.loadingController.dismiss();
}
this.loadingPresent = false;
}
检查一下!
阅读这些解决方案后,我想出了一个解决方案,可以防止装载机堆叠等问题。效果很好!
import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
import { LoadingOptions } from '@ionic/core';
import { TranslateService } from '@ngx-translate/core';
import { isNil } from 'lodash-es';
import { BehaviorSubject } from 'rxjs';
import { filter } from 'rxjs/operators';
enum LoadingTypeEnum {
show,
hide,
message,
}
@Injectable({
providedIn: 'root',
})
export class LoadingService {
/**
* this is a special behavior subject we can use on an inital load to show or hide a background etc.
* EXAMPLE: on inital profile load, we might want to have ngIf on an overlay and simply listen for this event.
*/
public appLoaded$ = new BehaviorSubject<boolean>(false);
public loading$: BehaviorSubject<{ type: LoadingTypeEnum; data?: any }> = new BehaviorSubject<any>({ type: LoadingTypeEnum.hide });
loadingState: { type: LoadingTypeEnum; data?: any } = null;
public loading: HTMLIonLoadingElement = null;
public loaderLoaded = false;
public i;
public spinningUp = false;
constructor(private loadingController: LoadingController, private translate: TranslateService) {
const l$ = this.loading$.pipe();
l$.pipe(filter((l) => l.type === LoadingTypeEnum.show)).subscribe((l) => this.showLoading(l.data));
l$.pipe(filter((l) => l.type === LoadingTypeEnum.hide)).subscribe(() => this.hideLoading());
}
show(opts?: LoadingOptions) {
if (isNil(opts)) {
opts = {
message: 'Please wait...', // this.translate.instant('PLEASE_WAIT'),
};
}
this.loading$.next({ type: LoadingTypeEnum.show, data: opts });
}
hide() {
this.loading$.next({ type: LoadingTypeEnum.hide });
}
message(m: string) {
this.loading$.next({ type: LoadingTypeEnum.message, data: m });
}
private async showLoading(opts: LoadingOptions) {
if (!this.loading && !this.spinningUp) {
this.spinningUp = true;
this.loading = await this.loadingController.create(opts);
await this.loading.present();
this.spinningUp = false;
}
}
private async hideLoading() {
const t = setTimeout(() => {
if (this.loading && !this.spinningUp) {
this.loading.dismiss().then(() => {
this.loading = null;
this.spinningUp = false;
clearTimeout(t);
});
}
}, 1000);
}
}
另一种使用 RxJs 的方法:
import {Injectable} from '@angular/core';
import {LoadingController} from '@ionic/angular';
import {BehaviorSubject, of} from 'rxjs';
import {filter, pairwise, scan, switchMap} from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class LoadingService {
private dialog;
private toggleLoading$ = new BehaviorSubject<number>(0);
constructor(private loadingController: LoadingController) {
this.toggleLoading$.pipe(
scan((acc, curr) => acc + curr, 0),
pairwise(),
switchMap(([prev, curr]) => {
if (prev <= 0 && curr > 0) {
return this.loadingController.create();
}
if (prev > 0 && curr <= 0) {
this.dialog?.dismiss();
}
return of(null)
}),
filter(d => !!d)
).subscribe((d) => {
d.present();
this.dialog = d;
});
}
showLoading() {
this.toggleLoading$.next(1);
}
hideLoading() {
this.toggleLoading$.next(-1);
}
}
第一个选项是值得推荐的,但我使用了这个代码。适合我。
setTimeout(() => {
this.loading.dismiss();
}, 1500)
我使用 "Ionic Loading Controller" 来显示微调器,直到检索到数据然后调用 "dismiss()" 将其关闭。 它工作正常,但有时当应用程序已经有数据时,"dismiss()" 在 "create()" 和 "present()" 完成之前被调用,这将保持微调器不被关闭...
我尝试调用"loadingController.present().then()"里面的数据,但是导致数据变慢了...
这是一个错误吗? 如何解决这个问题?
我的代码示例:
customer: any;
constructor(public loadingController: LoadingController, private customerService: CustomerService)
ngOnInit() {
this.presentLoading().then(a => consloe.log('presented'));
this.customerService.getCustomer('1')
.subscribe(customer => {
this.customer = customer;
this.loadingController.dismiss().then(a => console.log('dismissed'));
}
}
async presentLoading() {
const loading = await this.loadingController.create({
message: 'wait. . .',
duration: 5000
});
return await loading.present();
}
这就是我解决问题的方法..
我使用布尔变量 "isLoading" 在调用 dismiss() 时更改为 false。 在 present() 完成后,如果 "isLoading" === false (意味着 dismiss() 已经调用)那么它将立即关闭。
另外,我把代码写在一个服务里,这样我就不用在每个页面都重新写了。
loading.service.ts
import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Injectable({
providedIn: 'root'
})
export class LoadingService {
isLoading = false;
constructor(public loadingController: LoadingController) { }
async present() {
this.isLoading = true;
return await this.loadingController.create({
// duration: 5000,
}).then(a => {
a.present().then(() => {
console.log('presented');
if (!this.isLoading) {
a.dismiss().then(() => console.log('abort presenting'));
}
});
});
}
async dismiss() {
this.isLoading = false;
return await this.loadingController.dismiss().then(() => console.log('dismissed'));
}
}
然后只需从页面调用 present() 和 dismiss()。
相关示例:
customer: any;
constructor(public loading: LoadingService, private customerService: CustomerService)
ngOnInit() {
this.loading.present();
this.customerService.getCustomer('1')
.subscribe(
customer => {
this.customer = customer;
this.loading.dismiss();
},
error => {
console.log(error);
this.loading.dismiss();
}
);
或者,您必须像下面这样更改调用加载的代码
async ngOnInit() {
const loading = await this.loadingController.create();
await loading.present();
this.customerService.getCustomer('1')
.subscribe(customer => {
this.customer = customer;
loading.dismiss();
}
}
我正在使用类似的解决方案,但依赖于加载叠加层的 ID,并让离子加载控制器管理应该在顶部的叠加层。
加载服务
import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Injectable({
providedIn: 'root'
})
export class LoadingService {
constructor(public loadingController: LoadingController) { }
async present(loadingId: string, loadingMessage: string) {
const loading = await this.loadingController.create({
id: loadingId,
message: loadingMessage
});
return await loading.present();
}
async dismiss(loadingId: string) {
return await this.loadingController.dismiss(null, null, loadingId);
}
}
Components/Services 使用 LoadingService
import { LoadingService } from '../loading/loading.service';
@Injectable({
providedIn: 'root'
})
export class MessagesService {
...
constructor(
protected http: HttpClient,
protected loading: LoadingService
) { }
...
protected async loadMessagesOverview() {
const operationUrl = '/v1/messages/overview';
await this.loading.present('messagesService.loadMessagesOverview', 'Loading messages...');
this.http.get(environment.apiUrl + operationUrl)
.subscribe((data: Result) => {
...
this.loading.dismiss('messagesService.loadMessagesOverview');
}, error => {
...
this.loading.dismiss('messagesService.loadMessagesOverview');
console.log('Error getting messages', error);
});
}
}
对于 Ionic 4 检查此解决方案
来源Link
import { Component } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
loaderToShow: any;
constructor(
public loadingController: LoadingController
) {
}
showAutoHideLoader() {
this.loadingController.create({
message: 'This Loader Will Auto Hide in 2 Seconds',
duration: 20000
}).then((res) => {
res.present();
res.onDidDismiss().then((dis) => {
console.log('Loading dismissed! after 2 Seconds');
});
});
}
showLoader() {
this.loaderToShow = this.loadingController.create({
message: 'This Loader will Not AutoHide'
}).then((res) => {
res.present();
res.onDidDismiss().then((dis) => {
console.log('Loading dismissed! after 2 Seconds');
});
});
this.hideLoader();
}
hideLoader() {
setTimeout(() => {
this.loadingController.dismiss();
}, 4000);
}
}
我遇到了同样的问题,也许我有一个使用离子事件本身的更简单、更可靠的解决方案。这对我有用。它将等到创建加载程序,然后才完成服务调用,只有当服务调用完成时,才会关闭加载程序。希望对您有所帮助..
yourFuncWithLoaderAndServiceCall(){
this.presentLoading().then(()=>{
this.xyzService.getData(this.ipObj).subscribe(
res => {
this.dismissLoading();
this.dismissLoading().then(() => {
this.responseObj = res;
})
}
});
}
async presentLoading() {
this.loader = await this.loadingController.create({
translucent: true
});
await this.loader.present();
}
async dismissLoading() {
await this.loader.dismiss();
}
虽然公认的解决方案可以工作...我认为最好始终只加载 1 次。我的解决方案取消了以前的加载,如果它存在,并创建新的加载。我通常一次只想显示 1 个加载(我的特定用例),所以这个解决方案对我有用。
接受的解决方案提出了可能出现孤立加载的问题。但这是一个很好的起点。
因此,这是我建议的注射服务(如果需要,您可以使用更多的离子设置对其充电。我不需要它们,所以我没有添加more in the present function, 但可以相应添加):
import {Injectable} from '@angular/core';
import {LoadingController} from '@ionic/angular';
@Injectable({
providedIn: 'root'
})
export class LoadingService {
currentLoading = null;
constructor(public loadingController: LoadingController) {
}
async present(message: string = null, duration: number = null) {
// Dismiss previously created loading
if (this.currentLoading != null) {
this.currentLoading.dismiss();
}
this.currentLoading = await this.loadingController.create({
duration: duration,
message: message
});
return await this.currentLoading.present();
}
async dismiss() {
if (this.currentLoading != null) {
await this.loadingController.dismiss();
this.currentLoading = null;
}
return;
}
}
简单的方法是添加 setTimeOut 函数:
setTimeout(() => {
this.loading.dismiss();
}, 2000);
我遇到了同样的问题,显然我是通过首先确定问题来解决的。这个问题发生在加载器的持续时间过期时,所以它基本上在我们没有完全控制的情况下被解雇了。
现在,它将正常工作,直到您也使用 dismiss()
手动。
因此,如果您要手动使用 dismiss()
持续时间,请在创建时删除持续时间。然后使用 setTimeout()
或者
// create loader
this.loader = this.loadingCtrl.create()
// show loader
this.loader.present().then(() => {})
// add duration here
this.loaderTimeout = setTimeout(() => {
this.hideLoader()
}, 10000)
然后在此处创建隐藏装载程序
// prepare to hide loader manually
hideLoader() {
if (this.loader != null) {
this.loader.dismiss();
this.loader = null
}
// cancel any timeout of the current loader
if (this.loaderTimeout) {
clearTimeout(this.loaderTimeout)
this.loaderTimeout = null
}
}
此 onDidDismiss() 事件应在调用 .present() 函数后创建。
示例:
this.loader.present().then(() => {
this.loader.onDidDismiss(() => {
console.log('Dismiss');
})
});
同样的问题,这里是我的解决方案(ionic 4 和 angular 7):
从接受的解决方案开始。
礼物创造一次装货 在 dismiss 函数中,我仅在 dimiss returns true
时将 isShowing 设置为 falseimport { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Injectable({
providedIn: 'root'
})
export class LoadingService {
isDismissing: boolean;
isShowing: boolean;
constructor(public loadingController: LoadingController) {
}
async present() {
if(this.isShowing){
return
}
this.isShowing = true
await this.loadingController.create({spinner: "dots"}).then(re => {
re.present()
console.log("LoadingService presented", re.id)
})
}
async dismiss() {
if(this.isShowing){
await this.loadingController.dismiss().then(res => {
if(res){
this.isShowing = false
console.log("LoadingService dismissed", res);
}
})
}
}
}
以下是我在项目中解决相同问题的方法。我在 HTTP 拦截器中使用此服务来显示应用程序中所有 REST API 调用的加载器。
loading.service.ts
import {Injectable} from '@angular/core';
import {LoadingController} from '@ionic/angular';
@Injectable({
providedIn: 'root'
})
export class LoadingService {
constructor(public loadingController: LoadingController) {
}
async present(options: object) {
// Dismiss all pending loaders before creating the new one
await this.dismiss();
await this.loadingController
.create(options)
.then(res => {
res.present();
});
}
/**
* Dismiss all the pending loaders, if any
*/
async dismiss() {
while (await this.loadingController.getTop() !== undefined) {
await this.loadingController.dismiss();
}
}
}
在原来的问题上下文中,这可以像下面这样使用:
...
import {LoadingService} from '/path/to/loading.service';
...
customer: any;
constructor(public loadingService: LoadingService, private customerService: CustomerService)
ngOnInit() {
this.loadingService.present({
message: 'wait. . .',
duration: 5000
});
this.customerService.getCustomer('1')
.subscribe(customer => {
this.customer = customer;
this.loadingService.dismiss();
}
}
我知道这个问题是一年前问的。我面临同样的问题。我只想 post 我的解决方案。希望即将到来的访客能得到帮助。
async dismissLoading() {
console.log("dismiss");
this.isLoading = false;
}
private async presentLoading(msg) {
console.log("loading");
const loading = await this.loadingCtrl.create({
message: msg,
});
await loading.present();
var timer = setInterval(() => {
if (!this.isLoading) {
loading.dismiss();
clearInterval(timer);
console.log("set dismiss");
}
}, 1000);
}
async loadingmsg() {
this.isLoading = true;
await this.presentLoading("Please wait while...");
}
这个解决方案对我有用。如有不妥请指正
在尝试了一切之后,这就是我最终想出的办法。到目前为止似乎运作良好。
尝试使用间隔为 500 毫秒的 setInterval。我还尝试使函数保持非异步,以便在消费端可以轻松使用它。
import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Injectable({ providedIn: 'root' })
export class UiService {
constructor(private loading: LoadingController) { }
private loader: HTMLIonLoadingElement;
private loaderLoading = false;
public showLoading(message: string) {
this.loaderLoading = true;
this.loading.create({
message,
showBackdrop: true
}).then(load => {
this.loader = load;
load.present().then(() => { this.loaderLoading = false; });
});
}
public dismissLoading() {
const interval = setInterval(() => {
if (this.loader || !this.loaderLoading) {
this.loader.dismiss().then(() => { this.loader = null; clearInterval(interval)});
} else if (!this.loader && !this.loaderLoading) {
clearInterval(interval);
}
}, 500);
}
}
使用列表对我来说效果更好
import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Injectable({providedIn: 'root'})
export class LoadingService {
private loaders = new Array<HTMLIonLoadingElement>();
constructor(public loadingController: LoadingController) { }
present(options?: object) {
if (this.loaders.length === 0) {
this.loadingController.create(options).then(loader => {
this.loaders.push(loader);
loader.present();
});
}
}
async dismiss() {
if (this.loaders && this.loaders.length > 0) {
this.loaders.forEach(async loader => {
await loader.dismiss()
.then(() => {
loader = null;
})
.catch(e => console.log(e))
.finally(() => this.loaders = new Array<HTMLIonLoadingElement>());
});
}
}
}
我在使用 Ionic 4 加载控制器时遇到了同样的问题。 经过反复试验,我找到了可行的解决方案。
因为加载控制器函数正在使用 async 和 await,因为它们都是异步函数。
dismiss() 函数将在 present() 函数之前调用,因为 dismiss 函数不会等到创建和呈现加载程序,它会在 present() 函数调用之前触发。
下面是工作代码,
loading:HTMLIonLoadingElement;
constructor(public loadingController: LoadingController){}
presentLoading() {
if (this.loading) {
this.loading.dismiss();
}
return new Promise((resolve)=>{
resolve(this.loadingController.create({
message: 'Please wait...'
}));
})
}
async dismissLoading(): Promise<void> {
if (this.loading) {
this.loading.dismiss();
}
}
someFunction(){
this.presentLoading().then((loadRes:any)=>{
this.loading = loadRes
this.loading.present()
someTask(api call).then((res:any)=>{
this.dismissLoading();
})
})
}
通过这种方式,它还解决了并发 API 调用加载器解除问题的修复。 您也可以调用这些函数来形成拦截器。没有固定的持续时间,因为如果任何调用需要很多时间,加载程序将继续。但是,如果有人给出持续时间,那么如果 API 不会在此时停止,加载程序将停止
import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
@Injectable({
providedIn: 'root'
})
export class LoadingService {
isLoading = false;
loaderCounter = 0;
loading: HTMLIonLoadingElement;
constructor(public loadingController: LoadingController) {}
async present() {
this.loaderCounter = this.loaderCounter + 1;
if (this.loaderCounter === 1) {
this.isLoading = true;
const { loadingDuration, loadingMessage = loadingDefaultOptions.loadingMessage, loadingCssClass } = options;
this.loading = await this.loadingController.create({
duration: loadingDuration,
message: loadingMessage,
cssClass: loadingCssClass
});
await this.loading.present();
}
}
async dismiss() {
this.loaderCounter = this.loaderCounter - 1;
if (this.loaderCounter === 0) {
this.isLoading = false;
await this.loading.dismiss();
}
}
}
我找到了一种新方法来做到这一点。我希望它有所帮助! 它使用的是加载的id。所以如果你有很多加载,你不想忽略错误的加载。
服务中:
async showLoading(loadingId: string, loadingMessage: string = 'Loading...') {
const loading = await this.loadingCtrl.create({
id: loadingId,
message: loadingMessage,
spinner: 'circles'
});
return await loading.present();
}
async dismissLoader(loadingId: string) {
return await this.loadingCtrl.dismiss(null, null, loadingId).then(() => console.log('loading dismissed'));
}
在调用加载的组件中:
await this.globalVars.showLoading('ifOfLoading')
正在关闭加载:
this.globalVars.dismissLoader('ifOfLoading')
我对这个问题的解决方案是设置一个状态变量。这是:
@Injectable()
export class LoaderSerive {
private status: 'pending' | 'dismissed' | 'present' = 'dismissed';
constructor(public loadingCtrl: LoadingController) {}
public show() {
if (this.status === 'present') {
this.hide();
}
this.status = 'pending';
this.loadingCtrl.create({
id: 'spoon-indicator-1',
spinner: null,
message: `
<div>
<div class="loading-indicator--position">
<div class="loading-indicator">
<div class="bowl">
<div class="spoon"></div>
<div class="bowl-content"></div>
</div>
</div>
</div>
</div>`,
duration: 6000
})
.then((loader) => loader.present())
.then(() => {
if (this.status === 'pending') {
this.status = 'present';
} else {
this.hide();
}
});
}
public hide() {
this.loadingCtrl
.dismiss(null, undefined, 'spoon-indicator-1')
.catch((err) => Utilities.log('Loader error!', err))
.then(() => this.status = 'dismissed');
}
}
离子 5 - 简单而简短,使用 setTimeout,setInterval 与其说是解决方案,不如说是一种变通方法。
在我的例子中,我有 presentLoading 方法异步和 dismissLoading 方法同步..导致这个问题。
我刚刚将 async await 添加到我的 dismissoading 中,它工作得很好。对于没有“覆盖不存在”错误的安全开关,添加了一个布尔值,仅在加载程序存在时才关闭
async presentLoading() {
this.loadingPresent = true;
const loading = await this.loadingController.create({
message: 'Loading...',
});
return await loading.present();
}
async dismissLoading() {
if (this.loadingPresent) {
await this.loadingController.dismiss();
}
this.loadingPresent = false;
}
检查一下!
阅读这些解决方案后,我想出了一个解决方案,可以防止装载机堆叠等问题。效果很好!
import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
import { LoadingOptions } from '@ionic/core';
import { TranslateService } from '@ngx-translate/core';
import { isNil } from 'lodash-es';
import { BehaviorSubject } from 'rxjs';
import { filter } from 'rxjs/operators';
enum LoadingTypeEnum {
show,
hide,
message,
}
@Injectable({
providedIn: 'root',
})
export class LoadingService {
/**
* this is a special behavior subject we can use on an inital load to show or hide a background etc.
* EXAMPLE: on inital profile load, we might want to have ngIf on an overlay and simply listen for this event.
*/
public appLoaded$ = new BehaviorSubject<boolean>(false);
public loading$: BehaviorSubject<{ type: LoadingTypeEnum; data?: any }> = new BehaviorSubject<any>({ type: LoadingTypeEnum.hide });
loadingState: { type: LoadingTypeEnum; data?: any } = null;
public loading: HTMLIonLoadingElement = null;
public loaderLoaded = false;
public i;
public spinningUp = false;
constructor(private loadingController: LoadingController, private translate: TranslateService) {
const l$ = this.loading$.pipe();
l$.pipe(filter((l) => l.type === LoadingTypeEnum.show)).subscribe((l) => this.showLoading(l.data));
l$.pipe(filter((l) => l.type === LoadingTypeEnum.hide)).subscribe(() => this.hideLoading());
}
show(opts?: LoadingOptions) {
if (isNil(opts)) {
opts = {
message: 'Please wait...', // this.translate.instant('PLEASE_WAIT'),
};
}
this.loading$.next({ type: LoadingTypeEnum.show, data: opts });
}
hide() {
this.loading$.next({ type: LoadingTypeEnum.hide });
}
message(m: string) {
this.loading$.next({ type: LoadingTypeEnum.message, data: m });
}
private async showLoading(opts: LoadingOptions) {
if (!this.loading && !this.spinningUp) {
this.spinningUp = true;
this.loading = await this.loadingController.create(opts);
await this.loading.present();
this.spinningUp = false;
}
}
private async hideLoading() {
const t = setTimeout(() => {
if (this.loading && !this.spinningUp) {
this.loading.dismiss().then(() => {
this.loading = null;
this.spinningUp = false;
clearTimeout(t);
});
}
}, 1000);
}
}
另一种使用 RxJs 的方法:
import {Injectable} from '@angular/core';
import {LoadingController} from '@ionic/angular';
import {BehaviorSubject, of} from 'rxjs';
import {filter, pairwise, scan, switchMap} from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class LoadingService {
private dialog;
private toggleLoading$ = new BehaviorSubject<number>(0);
constructor(private loadingController: LoadingController) {
this.toggleLoading$.pipe(
scan((acc, curr) => acc + curr, 0),
pairwise(),
switchMap(([prev, curr]) => {
if (prev <= 0 && curr > 0) {
return this.loadingController.create();
}
if (prev > 0 && curr <= 0) {
this.dialog?.dismiss();
}
return of(null)
}),
filter(d => !!d)
).subscribe((d) => {
d.present();
this.dialog = d;
});
}
showLoading() {
this.toggleLoading$.next(1);
}
hideLoading() {
this.toggleLoading$.next(-1);
}
}
第一个选项是值得推荐的,但我使用了这个代码。适合我。
setTimeout(() => {
this.loading.dismiss();
}, 1500)