4

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.

5
  • Did you try using just $scope instead of $rootScope? Commented May 27, 2014 at 12:59
  • @callmekatootie Yup. Same outcome Commented May 27, 2014 at 13:07
  • Since you mentioned something about "fetching data", are you aware of the resolve property of $routeProvider route-objects ? Commented May 27, 2014 at 13:14
  • While I meant the URL by "data", this is actual a pretty good idea. I'll try, thank you Commented May 27, 2014 at 13:17
  • not able to understand your use-case. Can you create a plnker for this? Commented May 27, 2014 at 13:38

2 Answers 2

7

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Answers like these are why I love this site. Big thanks for your efforts! I shoot for a simple service, yet it is nice to see that solution.
I just realized I never linked to the actual demo (just a docs page). Fixed :)
ExpertSystem, a seriously big time thank you for this!
Almost perfect, but I got /company/edit/:id? instead of getting the complete url... with that id.
@sylouuu: Hm...I think you can get hold on the route parameters inside the resolve function (using $routeParams).
-1

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

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

});

1 Comment

This won't trigger when calling the view for the first time, too

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.