Ionic-framework: Toast or Alert Controllers throw an error when user is offline

Created on 9 Feb 2019  Â·  19Comments  Â·  Source: ionic-team/ionic-framework

Bug Report

Ionic version:


[x] 4.0

Current behavior:

Toast or Alert controllers cannot be used when there is not connectivity. I want to display a toast message when the user goes offline:

public async showOffline() {

const toast: any = await this.toastCtrl.create({
  message: "You are OFFLINE",
  duration: 5000
});
await toast.present();

}

This works fine online but as soon as I got offline I get an error.
This happens in the browser.

Expected behavior:

Toast message is displayed in the browser.

Steps to reproduce:

Create a method to display toast:
public async showOffline() {

const toast: any = await this.toastCtrl.create({
  message: "You are OFFLINE",
  duration: 5000
});
await toast.present();

}

Detect when user is offline:

this.connectionService.monitor().subscribe(isConnected => {
this.log.debug("isConnected", isConnected);
if (!isConnected) {
this.alertService.showOffline();
this.online = false;
} else {
this.online = true;
}
});
I'm using this package: ng-connection-service

Related code:

this.connectionService.monitor().subscribe(isConnected => {
this.log.debug("isConnected", isConnected);
if (!isConnected) {
this.alertService.showOffline();
this.online = false;
} else {
this.online = true;
}
});

.....

public async showOffline() {

const toast: any = await this.toastCtrl.create({
  message: "You are OFFLINE",
  duration: 5000
});
await toast.present();

}

Other information:

Stack trace:

13:27:55,919 EMPOWER isConnected [false]
bootstrap:145 GET http://localhost:8100/0.js net::ERR_INTERNET_DISCONNECTED
requireEnsure @ bootstrap:145
webpackAsyncContext @ ..entry.js$ include: .entry.js$ namespace object:810
o @ ionic.core.js:6
t.s @ ionic.core.js:9
lt @ ionic.core.js:9
(anonymous) @ ionic.core.js:9
v @ ionic.core.js:9
(anonymous) @ ionic.core.js:9
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:391
onInvoke @ core.js:17289
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:390
push../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:150
(anonymous) @ zone.js:889
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:423
onInvokeTask @ core.js:17280
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:422
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:195
drainMicroTaskQueue @ zone.js:601
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:502
invokeTask @ zone.js:1744
globalZoneAwareCallback @ zone.js:1770
bootstrap:145 GET http://localhost:8100/158.js net::ERR_INTERNET_DISCONNECTED
requireEnsure @ bootstrap:145
webpackAsyncContext @ .
.entry.js$ include: .entry.js$ namespace object:810
o @ ionic.core.js:6
t.s @ ionic.core.js:9
lt @ ionic.core.js:9
(anonymous) @ ionic.core.js:9
v @ ionic.core.js:9
(anonymous) @ ionic.core.js:9
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:391
onInvoke @ core.js:17289
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:390
push../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:150
(anonymous) @ zone.js:889
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:423
onInvokeTask @ core.js:17280
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:422
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:195
drainMicroTaskQueue @ zone.js:601
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:502
invokeTask @ zone.js:1744
globalZoneAwareCallback @ zone.js:1770
core.js:15714 ERROR Error: Uncaught (in promise): Error: Loading chunk 0 failed.
(error: http://localhost:8100/0.js)
Error: Loading chunk 0 failed.
(error: http://localhost:8100/0.js)
at HTMLScriptElement.onScriptComplete (bootstrap:133)
at HTMLScriptElement.wrapFn (zone.js:1332)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
at Object.onInvokeTask (core.js:17280)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
at ZoneTask.push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (zone.js:498)
at invokeTask (zone.js:1744)
at HTMLScriptElement.globalZoneAwareCallback (zone.js:1770)
at HTMLScriptElement.onScriptComplete (bootstrap:133)
at HTMLScriptElement.wrapFn (zone.js:1332)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
at Object.onInvokeTask (core.js:17280)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
at ZoneTask.push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (zone.js:498)
at invokeTask (zone.js:1744)
at HTMLScriptElement.globalZoneAwareCallback (zone.js:1770)
at resolvePromise (zone.js:831)
at resolvePromise (zone.js:788)
at zone.js:892
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
at Object.onInvokeTask (core.js:17280)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
at drainMicroTaskQueue (zone.js:601)
at ZoneTask.push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (zone.js:502)
at invokeTask (zone.js:1744)

Ionic info:

Ionic:

ionic (Ionic CLI) : 4.10.1 (/usr/local/lib/node_modules/ionic)
Ionic Framework : @ionic/angular 4.0.0
@angular-devkit/build-angular : 0.12.4
@angular-devkit/schematics : 7.2.4
@angular/cli : 7.2.4
@ionic/angular-toolkit : 1.3.0

System:

NodeJS : v8.11.4 (/usr/bin/node)
npm : 6.7.0
OS : Linux 4.19

triage

Most helpful comment

In your controller's constructor, add:

  constructor(public toastController: ToastController) {
    // HACK: fix toast not presented when offline, due to lazy loading the toast controller.
    // Can be removed once #17450 is resolved: https://github.com/ionic-team/ionic/issues/17450
    this.toastController.create({ animated: false }).then(t => { t.present(); t.dismiss(); });
  }

present() -> dismiss() is faster than duration: 1, and with no animated, it's not visible at all..
@raparri01 create() alone is not enough, still one chunk missing.

All 19 comments

Same problem here, did you manage to fix it?

I have the Toast on a Service and call the public method to show the toast from one component.

This issue happens only when you are offline, my guess is that is an issue with most of the Ionic controllers and may be related to lazy loading.

Thanks for the issue! If this is still an issue in latest, could you provide a repository or a minimal amount of easy to follow steps to reproduce? Thanks!

@brandyscarney the code in the description is the minimal amount, it is quite easy to reproduce. It is described in the ticket

Just ran into this. Seems like it is caused by trying to use Ionic components in error messages/dialogs when there are network failures. That triggers the error because Ionic can't reach over the network to dynamically load the component.

Is there any way to force Ionic to load a subset of it's components early so we can use Ionic for network error messages?

I am running into a similar error. I want to achieve the same functionality, but I don't get an error message. this.toastController.create() simply does not return a promise.

My Code:

window.addEventListener('offline', () => this.showToast())
async showToast() {
    let offlineToast = await this.toastController.create({
      message: 'You are offline',
      duration: 2000,
      position: 'top'
    })
    return offlineToast.present();
}

The cause of the problem is that toast is lazy loaded and it's not called until after you've disconnected, if you're testing this with livereload you'll definitely experience this issue. If you want to confirm this, trigger a toast event from the same controller prior to switching offline.

I don't know how to NOT lazy load a component — any help would be appreciated.

I am also running into a similar issue. Whenever I try to use the AlertController / Component without an internet connection it raises me an error. I have tested with emulators and devices, and the error still persists.

Is there any update on this issue? Or any other way that we could bypass this problem? I know we could use the native javascript 'alert' function, but is not the same as the one Ionic provides.

Best regards,
Bruna.

@brurubio I haven't found a way around it. What I have started doing is removing Ionic controllers and components as much as possible from our PWA. In the case of Alerts, I am replacing it with code that uses Angular Material since that will keep working in offline. I have also had to remove all usage of ion-icon from our code base because it has the same issue. I am replacing those with mat-icon with embedded svgs. Definitely a pain, but it is the only way I see right now to ensure a PWA can keep working when the network fails for a bit.

Any updates on this? Like others mentioned, I am also having this issue when using the ToastController to display a network unavailable message when offline. If it helps any, I am using Capacitor's Network API to detect if offline. Thanks.

@jasonruesch my work around was to have toast show a message when the app starts up. That way the toastController is loaded. When I go offline it loads properly no problem.

I used a similar workaround as @pvandrunen but creating a toast without presenting it successfully loads the toast controller for when the app goes offline.

In your controller's constructor, add:

  constructor(public toastController: ToastController) {
    // HACK: fix toast not presented when offline, due to lazy loading the toast controller.
    // Can be removed once #17450 is resolved: https://github.com/ionic-team/ionic/issues/17450
    this.toastController.create({ animated: false }).then(t => { t.present(); t.dismiss(); });
  }

present() -> dismiss() is faster than duration: 1, and with no animated, it's not visible at all..
@raparri01 create() alone is not enough, still one chunk missing.

I have the same issue. Any update, please? Please see the full error here with Ionic 4.6.2
https://stackoverflow.com/questions/57164430/ionic-4-and-toaster-with-network-capacitor-is-not-working-pwa-app-offline

@oori Thanks it works.

@oori the fix worked however the toast shows only once. If you dismiss the toast it does not appear again. any ideas?

Thanks for the issue. All Ionic components are lazy loaded to improve initial render time. If you need to account for offline network conditions, you should consider preloading the components needed by placing them inside of ion-app (with a display: none).

Example of a preloaded toast: https://codepen.io/liamdebeasi/pen/pojZqWX
Example of a non-preloaded toast: https://codepen.io/liamdebeasi/pen/ZEbjVXE

In each example, try loading the CodePen then turning Wi-Fi off and clicking the "Show Toast" button. In the non-preloaded example you should get an error, but in the pre-loaded example the toast should display properly.

I am going to close this as this is not a bug in Ionic Framework. Thanks!

@liamdebeasi This is awesome. Thanks!

Preloaded use case:

<ion-app>


  <ion-header>
    <ion-toolbar>
      <ion-title>Header</ion-title>
    </ion-toolbar>
  </ion-header>

  <ion-content class="ion-padding">
    <ion-button onclick="showToast()">Show Toast</ion-button>
  </ion-content>
  <ion-toast></ion-toast>
</ion-app>

```

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

Was this page helpful?
0 / 5 - 0 ratings