web-dev-qa-db-ja.com

Ionic 4: "Loadingcontroller" dismiss()はpresent()の前に呼び出され、終了せずに回転し続けます

「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();
}
20
rami bin tahin

これは私が私の問題を解決した方法です。

ブール変数「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();
    }
  );
62
rami bin tahin

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

  }
5
Code Spy

これが私のプロジェクトで同じ問題を解決した方法です。私はこのサービスを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();
  }
}
5
Andrii S.

リストを使うとうまくいきました

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>());
            });
        }
    }
}
2
Felipe Cardozo

このようにして、同時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();
    }
  }
}
2
Sudipta Ghosh

受け入れられた解決策は機能しますが...常に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;
    }

}
2
Martin

このonDidDismiss()イベントは、.present()関数が呼び出された後に作成する必要があります。

例:

this.loader.present().then(() => {
            this.loader.onDidDismiss(() => {
                console.log('Dismiss');
            })
        });
0
lehieusoftware

ここで同じ問題、そしてここで私の解決策(イオン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);
        }
      })
    }
  }
}
0
Martin

私は同じ問題に直面していました、多分私は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();
  }
0
kartik negandhi

簡単な方法はsetTimeOut関数を追加することです:

setTimeout(() => {
      this.loading.dismiss();
    }, 2000);
0
Ammar Bareesh

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

この問題に対する私の解決策は、ステータス変数を設定することでした。ここにあります:

@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');
    }
}
0
Yordan Nikolov

すべてを試した後、私が最終的に思いついたのはこれです。これまでのところ、うまく機能しているようです。

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);
    }
}
0
Faisal Rashid

この質問は約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...");
  }

この解決策は私にとってうまくいきます。私が間違っていたら訂正してください。

0
Anil

これを行う新しい方法を見つけました。お役に立てば幸いです。読み込みの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')
0
Raul Barros

私は同様のソリューションを使用していますが、ローディングオーバーレイのIDに依存し、Ionicローディングコントローラーがどのオーバーレイを上部に配置するかを管理しています。

LoadingService

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

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

}

0