Ionic 4: "Load Controller" увольняет() вызывается перед present(), который будет удерживать счетчик без отклонения

Я использовал "Ионный контроллер загрузки", чтобы отобразить счетчик, пока данные не будут восстановлены, тогда он называет "увольнять()", чтобы отклонить его. он работает нормально, но иногда, когда приложение уже имеет данные, "увольнять()" вызывается до того, как будут выполнены "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();
}

Ответ 1

вот так я решил свою проблему..

Я использовал булеву переменную isLoading, чтобы изменить на false при вызове dismiss(). после завершения 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();
    }
  );

примечание: не забудьте добавить "LoadingService" в провайдеры AppModule

Ответ 2

для 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);
    }

  }

Ответ 3

В то время как принятое решение может работать... Я думаю, что лучше всегда иметь 1 загрузку. Мое решение отклоняет предыдущую загрузку, если она существует, и создает новую. Я обычно хочу отображать только 1 загрузку за раз (мой конкретный вариант использования), поэтому это решение работает для меня.

Принятое решение ставит проблему возможных осиротевших нагрузок. Но это хорошая отправная точка 😊.

Поэтому, это мой предлагаемый инъекционный сервис (вы можете перезарядить его более ионными настройками, если вам это нужно. Они мне не нужны, поэтому я не добавил больше в настоящую функцию, но они могут быть добавлены соответственно):

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

}

Ответ 4

Вот как я решил ту же проблему в своем проекте. Я использую эту службу в HTTP-перехватчике, чтобы показать загрузчик для всех вызовов API REST внутри моего приложения.

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

Я использую аналогичное решение, но полагаюсь на идентификаторы загрузочных оверлеев и позволяю Ionic Loading Controller управлять тем, какой оверлей должен быть сверху.

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

Компоненты/Сервисы с использованием службы загрузки

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

}

Ответ 6

Я столкнулся с той же проблемой, может быть, у меня есть более простое и надежное решение с использованием самих ионных событий. Это сработало для меня. Он будет ждать, пока загрузчик не будет создан, и только тогда будет выполнен сервисный вызов, и только после завершения сервисного вызова только тогда загрузчик будет отклонен. Надеюсь, это поможет..

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

Ответ 7

Простой способ - добавить функцию setTimeOut:

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

Ответ 8

Это событие onDidDismiss() должно создаваться после вызова функции .present().

Пример:

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

Ответ 9

Здесь та же проблема, и здесь мое решение (ионный 4 и угловой 7):

Начинали с закаленного раствора.

настоящее создает загрузку один раз. В функции dismiss я устанавливаю isShowing в false, только если dimiss возвращает true

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

Ответ 10

Кроме того, вы должны изменить код, где загрузка вызова, как показано ниже

async ngOnInit() {
  const loading = await this.loadingController.create();
  await loading.present();
  this.customerService.getCustomer('1')
  .subscribe(customer => {
    this.customer = customer;
    loading.dismiss();
  }
}

Ответ 11

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

Теперь он будет работать нормально, пока вы не используете dismiss 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
    }
}