Angular's internals are baffling me again.
I need to determine the previous route when a specific view is loaded.
This is how I have done it
app.controller('TrashCtrl',function($scope,$rootScope){
$rootScope.$on('$locationChangeSuccess',function(evt, absNewUrl, absOldUrl) {
var hashIndex = absOldUrl.indexOf('#');
var oldRoute = absOldUrl.substr(hashIndex + 2);
console.log(oldRoute);
});
});
Unfortunately I have to call the view that corresponds with that controller once before the logic starts to work. The first time when the controller fires, nothing is logged. Furthermore, after this initial load, the application will log every routeChange, even if the loaded view is not working with TrashCtrl
I would like it like this:
- When the view
Trash
(whose controller is TrashCtrl
) is loaded, I need the previous route or an empty string if this was the first one.
- It would be nice if this only fires when the actual
trash
route is called, not on every routechange.
How would one achieve this?
Edit:
Note that I am aware of the possibility of creating a custom service and writng each change to it. This is not what I want. I would like to fecth the data only when it is needed, e.g just when Trash
is called.
I tried what ever I could, but it seems there is no straightforward way to get access to the previous route's path inside of the $routeProvider
's resolve
property.
Just for fun, I implemented a (ridiculously complex) solution with the following attributes:
- It detects the previous route only if the
/trash
view is loaded (not for every route).
- It doesn't have to know anything about the rest of the routes.
- No extra configuration is needed when adding additional routes (this adds implementation complexity, but simplifies maintainance).
In words
Here is how it works in "plain" words:
In the resolve
object, it registers a listener for the next $routeChangeSuccess
event.
Once the event is captured, it unregisters the listener.
Once the listener is unregistered, it resolves a promise with value of the previous route's path.
The object injected into the trashCtrl
(from the resolve
property) is a function, that returns the aforementioned promise.
The controller, receives that function, calls it to get the promise and waits for the promise to get resolved with the previous route's path.
Simple as pie !
Note:
For the sake of "simplicity" I haven't taken into account the posibility of an error leading to $routeChangeError
(instead of $routeChangeSuccess
). One should probably take that into account and deregister the listeners, but even if you don't, there will be no harm - the listener will leave on until the $routeChangeSuccess
is fired once.
The code
The controller:
app.controller('trashCtrl', function ($scope, prevRoutePromiseGetter) {
prevRoutePromiseGetter().then(function (prevRoute) {
$scope.prevRoute = prevRoute || 'nowhere';
});
});
The resolve
object:
resolve: {
prevRoutePromiseGetter: function ($q, $rootScope) {
var deferred = $q.defer();
var dereg = $rootScope.$on('$routeChangeSuccess',
function(evt, next, prev) {
dereg();
deferred.resolve((prev.originalPath || '').substr(1));
}
);
return function () {
return deferred.promise;
};
}
}
See, also, this short demo.
You need to be using the $routeChangeStart and not the location change.
$rootScope.$on('$routeChangeStart', function(event, next, current) {
});