「Ionic Loading Controller」を使用して、データが取得されるまでスピナーを表示し、次に「dismiss()」を呼び出してそれを閉じました。それは正常に動作しますが、アプリにすでにデータがある場合、「create()」および「present()」が実行される前に「dismiss()」が呼び出され、スピナーを閉じずに維持します...
「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();
}
);
Ionic 4の場合、このソリューションを確認してください
ソース リンク
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);
}
}
これが私のプロジェクトで同じ問題を解決した方法です。私はこのサービスをHTTP Interceptorで使用して、アプリ内のすべての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();
}
}
リストを使うとうまくいきました
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>());
});
}
}
}
このようにして、同時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();
}
}
}
受け入れられた解決策は機能しますが...常に1つのロードだけを使用する方が良いと思います。私のソリューションでは、以前のロードが存在する場合はそれを却下し、新しいロードを作成します。私は通常、一度に1つのローディングのみを表示したいので(私の特定のユースケース)、この解決策が私に適しています。
受け入れられたソリューションは、孤立した読み込みの問題を引き起こします。しかし、それは良い出発点ですか????.
したがって、これは私の提案する注入可能なサービスです(必要に応じて、より多くのionic設定でそれをオーバーチャージできます。それらを必要としなかったので、私はしませんでした現在の関数にさらに追加しますが、それに応じて追加できます):
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;
}
}
このonDidDismiss()イベントは、.present()関数が呼び出された後に作成する必要があります。
例:
this.loader.present().then(() => {
this.loader.onDidDismiss(() => {
console.log('Dismiss');
})
});
ここで同じ問題、そしてここで私の解決策(イオン4とangular 7):
受け入れられたソリューションから始めました。
現在は読み込みを1回作成しますdismiss関数では、dimissが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);
}
})
}
}
}
私は同じ問題に直面していました、多分私はionicイベント自体を使用してより簡単で信頼性の高いソリューションを持っています。これは私にとってはうまくいきました。ローダーが作成されるまで待機し、その後サービスコールのみがサービスコールが完了したときにのみ、ローダーが終了します。これが役に立てば幸いです。
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();
}
簡単な方法はsetTimeOut関数を追加することです:
setTimeout(() => {
this.loading.dismiss();
}, 2000);
Ionic 4ローディングコントローラーを使用しているときに直面した同じ問題。試行錯誤の後、私は実用的な解決策を得ました。
コントローラー関数の読み込みは非同期を使用しているため、両方とも非同期関数であるため待機します。
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();
})
})
}
この問題に対する私の解決策は、ステータス変数を設定することでした。ここにあります:
@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');
}
}
すべてを試した後、私が最終的に思いついたのはこれです。これまでのところ、うまく機能しているようです。
500ms間隔で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);
}
}
この質問は約1年前に尋ねることです。私も同じ問題に直面しています。私は自分の解決策を投稿したいだけです。来たるお客様のお手伝いをお願いします。
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...");
}
この解決策は私にとってうまくいきます。私が間違っていたら訂正してください。
これを行う新しい方法を見つけました。お役に立てば幸いです。読み込みの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')
私は同様のソリューションを使用していますが、ローディングオーバーレイのIDに依存し、Ionicローディングコントローラーがどのオーバーレイを上部に配置するかを管理しています。
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);
}
}
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);
});
}
}