Killing Previous Route's Controller On Next Route - angularjs

I'm having an issue in my Angular app where if I arrive at one controller view which makes an $http.get() asynchonous call and navigate away to a different controller view before the promise can resolve then I effectively end up having functions from one controller executing while on a completely different controller.
For example if the first page does an $http.get() and then calls $window.location = data.goToUrl in the .success() function. Then if I open that first page, and navigate away before the .success() fires then when I arrive on the completely different page I was navigating to then when the first page's .success() method eventually fires off I will be navigated away from the new page which should never be navigating me anywhere normally.
How can I either cancel all promises or kill all asynchronous functions of a controller when I leave that controller to make sure it doesn't affect the next view? Or is there a better way of handling this issue?

No, you can't cancel requests which are already started. You should find another way to solve the problem, for example you can disable the button which is handling route by using ng-disable until your promise is rejected or resolved.

Related

In AngularJS, what if you are routing to the same page (same URL and hash)?

In an AngularJS Single Page Application, if you are in the main page and now you route to the second page, and use the "service" (as a global), and use myService.cityName to pull data using AJAX (by using $resource), that's fine.
But what if on your page header, you also have an input text box, and you can type in a city name, and when the user press Enter, you are routing to the same page (the second page). So I think browser didn't do anything because it is the exact same URL. How would you solve this issue or what is the AngularJS's way of handling this?
(Update: it is not to refresh or reload a page... it is about, say, you get weather data for a city, and you are on the forecast subpage, with a path of #/forecast. Now at the top search box on the page, you enter a different city and click "Submit" to go to the same path #/forecast then nothing will happen)
Update2: essentially, in my controller code:
$scope.submit = function() {
$location.path("/dataPage");
}
and my form is <form ng-submit="submit()">.
so if I am already on the dataPage, then now browser wants to go to dataPage to show new data, but since the path and hash is exactly the same, the browser just will not do anything. (I suppose due to no hashchange event happened, so nobody will notify AngularJS to do anything)
Your question is unclear, if you want a page refresh like F5, one solution is at "Solution for refresh page". But if you just want to reload things, you could follow "Solution for reload page".
Solution for refresh page:
To update a page, all that you need to update the model data of controller and the page will be updated accordingly. Ideally, you should never refresh an entire page in AngualrJS . If you need to do so, you are not using AngularJS correctly .
The $location service does not provide access to refreshing the entire page. If you need to refresh the entire page, you need to use the $window.location object.
$window.location.href = "YOURPAGEPATH";
Solution for reload page:
just want to reload things under ng-view, re-initialized the current route controller, you could do like below.
$route.reload("YOURPATH");
$route.reload() will reinitialise the controllers but not the
services.
If you want to reset the whole state of your application you can use:
$window.location.reload();
This is a standard DOM method which you can access injecting the $window service
Also see: $route documentation
According to $route documentation:
Causes $route service to reload the current route even if $location
hasn't changed. As a result of that, ngView creates new scope,
reinstantiates the controller.
Well you can just save data from request on your global service. And in controller you can bind that data, so if you press submit from header that function should just refresh your data in service.

in Angular. What's the best way to create an icon loading for pages?

I am using with ui-route by the way
But I want to create something useful for all the site
That every time there is a request to the server
the icon will appear
You can do this a number of ways. Write an angular service that you call inside every request that sets a variable to true when a request goes out, and false when the response comes back. Then attach an ng-show to an element with the icon set to the variable.
Also you can look into the $http interceptors, which might prove useful as then you would not have to call the service for every request manually. Downside, it would trigger on every request which may not be the desired effect.

Wait for app to finish initialization before changing route

When I start my app I have an initialization process that shows some loading indicator and shows the actual content after everything is loaded. Now when I change the Url manually, the initialization process is also triggered, which is good, but the view controller assigned to that route is also created and starts its work right away before the initialization is completed. I tried to use a resolve property at my routes, where I return a promise that is resolved once the app is loaded, however I put this promise in a service and thats forbidden to be injected during the config phase.
How can I wait for the app to be completely loaded before I change the route?

AngularJS routeprovider with named groups stop multiple instance of controller

When i setup a routeprovider that contains a named group via .when('/search/:searchString', { when the page is loaded for each different :searchString it loads a new instance of the controller assigned.
This causes me a problem when i have a $rootScope.$on('searchUpdated', becuase it reacts to the broadcast message on every instance of the controller.
Is there a way to make it only load one controller and use the same controller for each request, if not is there a way to destroy the controller when the page has left.
For anyone facing a similar issue:
The controller is destroyed, but listeners registered on the $rootScope still exist, since the $rootScope is never destroyed.
The problem seems to be your registering a listener on the $rootScope from every controller instance.

Angular reload current route and reload the current template

When a use visits a private page unauthorized, say profile, my backend 302 redirects to a controller action that serves up the login partial in place of the profile partial. Since it 302 redirects to an action that returns a partial, the url address bar doesn't change from the page the user was trying to access ("/profile").
I was going to "fix" that but actually I think it makes a good user experience instead of dealing with return urls as query params.
The idea is once they log in I just want to reload the current route aka do a GET request for the profile partial via "/profile" and switch it back in instead of the login partial.
However, I can't get this "reload current route" to work. I tried all of the following:
$location.$$compose();
$location.absUrl($location.path());
$location.url($location.path());
$location.path($location.path())
$route.reload();
But none work. $route.reload() seems to be the definite way but it also doesn't work. It goes through the route cycle, reinstantiates the controller, but does not do GET request to reload the template
The only thing that works is a hard refresh via location.reload() but that is not ideal.
How can I force angular to reload the template for the current route?
Ok I found the solution provided by lgalfaso on Github (exact paste):
Templates are
cached, if a user does not have the permissions to be in a page, then
this check should be done before it reaches the controller or after,
within the controller, but not on the template retrieval
If this is the way you want to follow, then you need to remove the
template from the $templateCache before you call reload
So that worked for me because login template actually gets cached as the template the user was trying to access. So removing it and letting angular re-fetch the correct one for the current route worked like a charm.
var currentPageTemplate = $route.current.templateUrl;
$templateCache.remove(currentPageTemplate);
$route.reload();
I have noticed that $route.reload() method re-instantiates everything that is setup on your $routeProvider.when("/someUrl",{controller:'SomeController',templateUrl:'SomeView.html'}) template,controller and/or any resolved promises you may have passed within the .when() method.
Therefore; when you build your app, if you want $route.reload() to reload all the page and re-instantiate controllers you must put everything under your <div ng-view></div> container and include any menus or footers inside the templateUrl file.

Resources