AngularJS - Get previous route when firing control

2019-05-08 06:16发布

问题:

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.

回答1:

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.



回答2:

You need to be using the $routeChangeStart and not the location change.

$rootScope.$on('$routeChangeStart', function(event, next, current) {

});