How to prevent a tab state change with $stateChangeStart ?!


#1

Hi!
I try to prevent a tab state change with a confirm dialog.
It doesn’t work, the state doesn’t change as expected BUT the view appears blank.
Any advice please?!
Note that this works for the link inside a tab but doesn’t work for a tab state change.
Please see the codepen and here is the code I have added in the controller (fork of the tabs and navigation demo) http://codepen.io/dbarr/pen/lnsIA

$rootScope.$on('$stateChangeStart',
			function (event, toState, toParams, fromState, fromParams) {

        console.log('toState.name: '+toState.name);
        console.log('fromState.name: '+fromState.name);
        
        if(confirm("Would you like to change state?")){
             console.log('go to: '+toState.name);
	} else {
             console.log('stay at state: '+fromState.name);
	     event.preventDefault();
	     //event.stopPropagation;
	}
});

#2

Are you just trying to prevent the navigation or have something happen before the change?


#3

@mhartington Hey, I am trying to have something happen before navigation.

Suppose I am on page ‘X’ and if user navigates to any other page, then I should Immediately stop the navigation and show a confirm box, if the dialog returns true then the page should navigate.

This is what I have done:

var foo = $scope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){
	event.preventDefault();
	$ionicPopup.confirm({
	   title: 'some title'
	}).then(function (res) {
	   if (res) {
	    $state.go('stateName')
	   } else {
	     return;
	   }
	});
		});
$scope.$on('$destroy', foo)

But this does not work. How should I do it?


#4

@mhartington
Actually I just try to prevent the navigation.
I wan’t to stay on the first tab if I do not confirm the change.
It works for basic links but not with a tab link.


#5

So I’m still looking into this, but what I’m getting now is a nice little loop with the popup.

Still trying to work it out, but I figure I should post so we can all come to a solution for this.


#6

Thanks for the help.
I’m not sure why, but when $stateChangeStart is raised, it’s already too late, the page is blank even if the state has not change yet. And preventing anything, at that time, doesn’t help.


#7

@mhartington Yes exactly. Even I get the loop.


#8

Hi,

It is still not working with beta 8: http://codepen.io/dbarr/pen/CHgmE
Does anybody have a solution for this?

Thanks.


#9

Seems like it works for me only if I press confirm. So what needs to be fixed is the error statement.

else {
  console.log('stay at state: '+fromState.name);
  event.preventDefault();
  //event.stopPropagation;
}

I’ll do some digging around on why this isn’t working


#10

The loop happens because on the resume selection, the $state.go triggers another $stateChangeStart which triggers another popup.


#11

Try this solution : http://codepen.io/calendee/pen/daigh

It’s not great because you have to manually implement the tab state change, but it prevents the problems with using $stateChangeStart

P.S. You could also use the $ionicTabsDelegate to make this work using $ionicTabsDelegate.select(??)


#12

Thanks Calendee.
Unfortunately, this doesn’t solve my problem.

The reason I asked about $stateChangeStart is because I also want the confirm dialog to pop up when the user uses the hard back button (Android) to go back to a previous tab state.
This can be simulated on Firefox or Chrome with the “Del” key on keyboard.

I should have mentioned that sorry.

Story : http://codepen.io/calendee/full/daigh
Click on “about tab”, confirm with “OK”.
Then hit the “del” key to go back to previous tab. No dialog appears.


#13

I thought you might then want to use something like $urlRouter.sync() from http://angular-ui.github.io/ui-router/site/#/api/ui.router.router.$urlRouter

Unfortunately, this does not seem to work either. The transition occurs before the pop-up responds. I think has something to do with how the tabs delegate deals with changing tabs.

I’m out of ideas. Mike, you have any update?


#14

@Calendee
@mhartington
Hi,
Do you have any tips for this?


#15

I think @Calendee solution is the best, but you could also include a custom back-button handler function.

$ionicPlatform.registerBackButtonAction(
  function () {
    $ionicPopup.confirm({
      title: 'some title'
    })
    .then(function (res) {
      if (res) {
        console.log("You want to go back")
        $ionicNavBarDelegate.back();

      } else {
        console.log("Cancelling navigation")
      }

    })
  }, 100
);

#16

Hi, There.
I tried prevent the back button on the desktop browser or mobile browser.
so I made like this:

$rootScope.$on(’$stateChangeStart’, function (event, toState, toParams, fromState, fromParams) {

console.log('toState.name: '+toState.name);
console.log('fromState.name: '+fromState.name);

// prevent go back when press the back button on login page.
if ( toState.name === 'prepare' && fromState.name === "login") {
  event.preventDefault();
  $state.go('login');
  return;
}
// prevent go back when press the back button on home page.
if ( toState.name === 'login' && fromState.name === "home") {
  event.preventDefault();
  $state.go('home');
  return;
}

});

First time, this worked when I press the backbutton but,
it’s not working if I tried again,

any help?


#17

I found a work-around that works for me. I believe the problem comes from the ionic tab bar. The tab bar already performs actions regarding the state change, while ui-router has not yet cleared the action for take-off.

In my scenario I wanted to event.preventDefault(), wait on a promise and considering the result of that promise either stay in the current state or continue with the state change (re-initiate). Staying in the current state does not work, since the tab bar has already decided to hide the current state/view. However, if you want to stay in the current state, you can just use $state.reload(), which will reload the current state and force the tab bar to show the original view/state again.

Example:

$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
    event.preventDefault(); // Prevent state change, wait on promise

    myPromise()
    .then(function() {
        $state.go(toState, toParams); // Continue with the initial state change
    })
    .catch(function() {
        $state.go('myState');
        if($state.current.name === 'myState') {
            $state.reload(); // We were already in this state, sync tab bar
        }
    });
});

#18

use ng-click instead of ui-sref. try if it works


#19

@mhartington given that solution was to remove control from the tab by using ng-click, seems there is something odd going with ion-tabs directive not playing nice with ui-router.

Shouldn’t this be addressed? If so, I can create an issue on github and put some code example there.