Equivalence of window.onbeforeunload in AngularJS for routes - angularjs

Regular JavaScript has window.onbeforeunload. How do I emulate the same in AngularJS with HTML5 routes?
There is $beforeRouteChange, but it doesn't allow you to cancel the event as far as I can tell.
To clarify: window.onbeforeunload would work for navigating away from the page, but not for intra page navigation, e.g. going from one controller to another just through the HTML5 history API.

Add this :
$scope.$on('$destroy', function() {
window.onbeforeunload = undefined;
});
$scope.$on('$locationChangeStart', function(event, next, current) {
if(!confirm("Are you sure you want to leave this page?")) {
event.preventDefault();
}
});

There is a $locationChangeStart event which can be canceled.
Since it hasn't been documented yet, here is the unit test describing how it affects the $route service.
https://github.com/angular/angular.js/blob/v1.0.1/test/ng/routeSpec.js#L63
This doesn't provide a confirmation for the user like window.onbeforeunload does. You need to bring your own dialog service and restart the location change process to get the same effect (or you could just use the synchronous $window.confirm).

If you are using angular-ui-router you need to use $stateChangeStart instead of $locationChangeStart.

When using UI-Router version 1.0.0+, use $transitions.onStart instead of $stateChangeStart. See the transition hooks documentation.
The $stateChange* events are deprecated as of version 1.0.0 (source):
All state events, (i.e. $stateChange* and friends) are now deprecated
and disabled by default. Instead of listening for events, use the
Transition Hook API.
Example code to abort a transition (source):
$transitions.onStart({}, function(transition) {
if (transition.to().name === 'unreachable') {
return false;
}
}

Related

Ui-Router otherwise rule with ng-admin

I have got a problem in an angular app, where I have integrated ng-admin to provide a simple admin panel. I have also integrated Authentication and want to point to a login state, when there is no current session.
Ng-admin itself sets ui-router's otherwise method to point directly to the dashboard.
Even when setting my own $urlRouterProvider.otherwise(...) I am not able to force ui-router to use my otherwise function.
I tried it like this:
$urlRouterProvider.otherwise(function ($injector) {
console.log('Hello World?!');
state.go('login');
});
But the console.log is never printed...
I would like to intercept the state transition to the dashboard, before any dashboard-code is run, and redirect the user to the login page first.
Any hints and ideas are greatly appreciated.
Thanks #user8175473 for pointing me into the right direction.
I have solved the problem using $on('$stateChangeStart) as $on('$stateChangeSuccess) is called after some state code is executed.
$rootScope.$on('$stateChangeStart', function(event, toState) {
if(toState.name !== 'login' && !service.isLoggedIn()) {
event.preventDefault();
$state.go('login');
}
});
Note that event.preventDefault() is needed to cancel the state transition completely.

How can I call an Angular function on each page view?

Right now I am using angular.element(document).ready(init()); but it calls init(); on every page refresh and not when browsing back and forth to the page. How could I call this function on every page view ?
I've tried also onload and ng-init and they don't work - the function doesn't get called.
I think this is what you're looking for:
$routeChangeSuccess Broadcasted after a route change has happened successfully. The resolve dependencies are now available in the
current.locals property.
ngView listens for the directive to instantiate the controller and
render the view.
This is what I do and it works for me:
$scope.$on('$routeChangeSuccess', function () {
// do something
});
Unless you're using ui-router. Then it's:
$scope.$on('$stateChangeSuccess', function () {
// do something
});
More info is found in the docs

$destroy event not working in angular

$scope.$on('$destroy', function (event){
$timeout.cancel(promiseObj);
});
If i am on a page that is being loaded(since the page contain $http request, it takes time to load data) and while loading, I change the page from navigation, the $timeout is not being deleted, and continuous http call are going. can you help?
Use $routeChangeStart instead of $destroy
$routeChangeStart
Broadcasted before a route change. At this point the route services starts resolving all of the dependencies needed for the route change to occur. Typically this involves fetching the view template as well as any dependencies defined in resolve route property. Once all of the dependencies are resolved $routeChangeSuccess is fired.
The route change (and the $location change that triggered it) can be prevented by calling preventDefault method of the event. See $rootScope.Scope for more details about event object.
So please try this below code.
$scope.$on('$routeChangeStart', function (scope, next, current) {
if (next.$$route.controller != "Your Controller Name") {
$timeout.cancel(promiseObj);// clear interval here
}
});
Actually, problem was angular created many objects with same name as promiseObj.
So, those object were not being deleted. So, I created an array of promiseObj[], and using for loop i deleted all the promises. ;)
$scope.$on('$destroy', function () {
for(var promise in promiseObj)
{
$timeout.cancel(promiseObj[promise]);
}
});

How to prevent route changing?

I have a service in which inside I bind a click event:
$('button').click(function() {
alert('Clicked');
return false;
});
The issue is when I do not start at the default "/" route (i.e. "/testroute"), then that same button when clicked, causes the page url to go to "/" and not fire my event at all. When I click on it again after the route changes to "/", the event triggers as normal. How do I make it such that if I were to start at /testroute (even though it has the same view, different controller, but shares the same service, the alert will fire?
Use locationChangeStart. Also read the link Andrey posted.
$rootScope.$on('$locationChangeStart', function(e) {
e.preventDefault();
});
You might want to use these events to prevent route changing.

Order of routeChangeStart event and rendering

I have a run function for a module and inside it there is a $routeChangeStart event binding. I would like to know time of the first routeChangeStart event triggered. I am expecting that it should be called immediately after first request but before any page render but it is not as I expected. It seems that the event is called after page started to be rendered.
module.run(function ($location, $rootScope) {
$rootScope.$on("$routeChangeStart", function (event, next, current) {
//do something with next.xxx
});
})
What is the expected behaviour? Or this is a bug?
The event is fired before the page starts rendering, but that doesn't mean you'll catch it before the rendering begins. The event gets fired, then the next thing in the call stack is when Angular begins the page rendering (fetching the template, waiting for the route resolve property, etc) and you catch the event after that. From the angular docs...
Broadcasted before a route change. At this point the route services
starts resolving all of the dependencies needed for the route change
to occur. Typically this involves fetching the view template as well
as any dependencies defined in resolve route property. Once all of the
dependencies are resolved $routeChangeSuccess is fired.
If you need to do something like conditionally preventing the change, try using the $locationChangeStart event instead. For example...
$scope.$on('$locationChangeStart', function (event) {
if (someCondition) {
event.preventDefault(); // prevent the change
}
});
This will be run before Angular starts loading the new page.

Resources