New instance of Alert Controller in Ionic 3


#1

This is in reference to the error described in this question

Kind of a newby question, but how do I create a new alert every time?

Currently I create the one I use by defining a function in the page class as per the docs:

private showAlert(msg: string, subTitle: string, buttons?:{}[])
   {
     let alert = this.alertCtrl
                 .create({
                           title: msg,
                           subTitle: subTitle,
                           buttons: buttons? buttons : ['OK']
                         });
     alert.present();  
 }

then calling it where I need it every time: this.showAlert("msg","subtitle");

But I get the same error described in that question:

AlertController Uncaught (in promise): inserted view was already destroyed

I tried defining a new controller where I call it but that didn’t help.

I am grateful for any help on this.


#2

Your error is weird enough that I have never encountered it. Something is wrong in code you have not posted.


#3

As far as creating and using the alert goes, that’s all I’m doing. Could anything else make a difference in the creation and destruction of alerts?

More interestingly, however, every time I try to trigger a new alert by the appropriate dom event and user action, a new alert does come up but then ionic displays that error message anyway. Once I click on close at the top right of the error (modal?) to dismiss the error, the newly created alert is still there and I can interact with it just fine.

I’d rather not post all of my code for the page since it’s a lot of code; but the gist of it is here.

Also, I’d like to try to debug my own code than ask someone to do it for me.


#4

You might be treating alert creation as synchronous, when it is actually asynchronous. Here’s a related method in an AlertManager provider I wrote. You’ll see that I am explicitly managing the Promise of displaying the alert.

 private presentOKalert(options: OkAlertOptions): Promise<any> {
  	let alert = this.alertCtrl.create({
			title: options.title || '',
			subTitle: options.subTitle || '',
			message: options.message || '',
			buttons: ['OK']
		});
  	return alert.present();
  }

#5

Hi Aaron,

Thanks for the reply.

I tried the change in implementation of the AlertController to no effect. I was under the impression that the alert is properly disposed of by Ionic when the user taps one of the buttons?

I get the feeling I may be missing something obvious. On the other hand, I wonder if how I create and present the controller might really be the issue since the error message implies something was trying to remove an alert which was already removed earlier.

Finally, the docs mention no special treatment in the case of multiple calls to the AlertController.

To be honest, at this point I’m at a loss to find out what’s going wrong.


#6

Eventually. Very little is instantaneous in web programming. Somewhere, you are assuming things happen faster than they really do.

Edit: Look at it this way. if you are not defining dismiss handlers, and if the word “then” appears nowhere in your code to handle Promise resolution, then you’re doing it wrong. You need at least one of those two approaches.


#7

This is really a strange error. One thing I noticed is the lack of a role being attached to your button. Shot in the dark, but maybe

buttons: [{ text: 'OK', role: 'cancel' }]

could possibly be a solution. I’ve never run into a problem but I use a method similar to @AaronSterling in that I return alert.present() as Promise<any>

presentAlert(title: string, subtitle: string): Promise<any> {
  	let alert = this.alertCtrl.create({
			title: title,
			subTitle: subtitle,
			buttons: [{text: 'OK', role: 'cancel'}]
		});
  	return alert.present();
  }

I also have set a private variable on my component to hold Alert.

private myAlert: Alert;
presentAlert(title: string, subtitle: string): Promise<any> {
  	this.myAlert = this.alertCtrl.create({
			title: title,
			subTitle: subtitle,
			buttons: [{text: 'OK', role: 'cancel'}]
		});
  	return this.myAlert.present();
  }

That way I can reference this.myAlert at other points in my component, outside of the function that is responsible for presenting it (I dont do this often, just special use cases)


#8

@whatisthiswtf , just to make sure. You’re importing

import { AlertController } from 'ionic-angular';

And in constructor

constructor(public alertCtrl: AlertController)

Yes?


#9

I don’t know how I could make use of the alert function with an asynchronous signature; I wanted to say it earlier but I call the alert through another function which runs when the user clicks something.

So, if I did this.showAlert("msg", "subtitle").then(_ => {}) or the like, the promise resolution would be part of the instance which was called on the first click. I’m not sure how I could carry over the resolution into future calls of my other function.

Finally, the demo source page for the alert controller shows no asynchronous handling of the controller and I can call the alert several times on the components page in the docs just fine.

I’m so lost :frowning:


#10

Hi jaydz,

Thank you for replying.

Yes, I’ve tried all of those caveats to no effect. (So sad :frowning:)

This really is unusual. Also, as I pointed out to @AaronSterling, the demo source page for the alert controller shows no such special love and care for promise resolution. (Again, so sad :frowning:)

Also, please reference my latest response to Aaron, as it contains more information.


#11

The alert API clearly shows that alert.present returns a Promise. It isn’t the fault of the intro docs that you are using alerts in an advanced, nonstandard way.


#12

I suppose I’m not really catching on to what your intentions are.


#13

@jaydz

Please see this: https://stackblitz.com/edit/ionic-ejmpzr

I’m using the controller the exact same way in my component and on stackblitz it works but with no promise handling.

If this is fine, then I think the problem may be elsewhere in my page class; so I’ll just have to go over the whole thing.

At any rate, I’m really grateful for your time on this.


#14

No problem.

I’m guessing so too. I’ve used AlertController without returning a promise (as you are doing) and didn’t have any issues. In those cases, I wasn’t doing anything complicated whatsoever though.

Must be interacting strangely with some other code.

Granted I didn’t look the code over with a fine-tooth comb


#15

Agree with @jaydz. The stackblitz code is fine. Your page is not respecting the asynchrony of the alert.


#16

@jaydz

You guys won’t believe what was causing the problem.

I was calling a Loading instance from the LoadingController as well before the program determined whether it was appropriate to show the alert. Right before the alert was to be displayed, I dismissed the loader to show the alert.

I removed my call to the LoadingController entirely and now everything works fine. (Masaka!)

This was really unexpected and I would have never imagined that this would be an issue.

I made sure I was handling the dismissal of the loader asynchronously and then showing the alert but that didn’t help either.

All said and done, I’m glad I could figure out what was causing the issue but I just wish it wasn’t so obscure.

Well, at least it got me to look at the page class, which is something I was putting off :confused:


#17

You used a structure like

loading.dismiss().then(_ => alert.present())
?
Because that would probably work.


#18

Oh yes.

Extra text for the minimum character requirement.


#19

@whatisthiswtf, Glad its working but yeah, as @AaronSterling mentions

loading.dismiss().then(_ => alert.present())

Is pretty standard.

Even without the promise chain it should work.

loading.dismiss();
alert.present()

There’s still something strange going on.

Out of curiosity do you have dismissOnPageChange set to true on your loading instance?

And are you presenting loading on ionViewDidLoad, willLoad, any lifecycle event, by chance?

I’ve had issues with loadingController when dismissOnPageChange is set to true and I present it during willLoad, willEnter, didLoad, etc

In hindsight, it may have thrown that same error


#20

Yes, my alert was presented as part of the promise resolution for the loader.

On the promise resolution for the alert, there was nothing to do, so the function calling it exited.

I don’t have the dismissOnPageChange option set, nor do I use the loader or alert on any lifecycle event. Also, any execution path which leads to the loader being dismissed and the alert being shown doesn’t trigger a page change. These were the paths I was testing when I found the error.

I don’t want to jump the gun here, but maybe this could be a bug?