Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

$routeChangeStart not triggered on load #15698

Closed
matthieusieben opened this issue Feb 10, 2017 · 2 comments
Closed

$routeChangeStart not triggered on load #15698

matthieusieben opened this issue Feb 10, 2017 · 2 comments

Comments

@matthieusieben
Copy link

matthieusieben commented Feb 10, 2017

Note: for support questions, please use one of these channels: https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#question. This repository's issues are reserved for feature requests and bug reports.

Do you want to request a feature or report a bug?
Not sure if bug or per-design.

What is the current behavior?
The $locationChangeStart and $locationChangeSuccess are both triggered when the script is bootstrapped. However, if no matching route is found, the $routeChangeStart gets never triggered, not even with null to notify an unmatched initial route.

Since the initial routing is done in an $evalAsync, it is very hacky to be able to detect the case were there is no route matching the initial path:

// $route.current is never set if we do this during bootstrap because it will be executed before the first $locationChangeStart is emitted (i.e. before $route.current is setup)
$scope.$evalAsync(() => {
  if (!$route.current) {
    // redirect to valid route
  }
})
// This will work but will cause flickering if we change stuff ($location.path() or view models)
$timeout(() => {
  if (!$route.current) {
    // redirect to valid route
  }
})
// This can be used to detect invalid initial route:
var unreg = $scope.$on('$locationChangeSuccess', function (event, next) {
  if ($route.current === undefined) {
    $scope.$broadcast('$routeChangeStart', undefined, undefined);
    $scope.$broadcast('$routeChangeError', undefined, undefined, new Error('Unmatched initial route'));
  }
  unreg();
});

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (template: http://plnkr.co/edit/tpl:yBpEi4).

http://plnkr.co/edit/eruQvzIzLWZE1vkdG91s?p=preview

Look at console while loading these urls:

What is the expected behavior?
$routeChangeStart should be triggered with undefined as next route when loading with a non existing path.

What is the motivation / use case for changing the behavior?
Be able to detect incorrect route during bootstrap of the app.

currently I need to have a first listener to $locationChangeSuccess (to be sure that the $route service was initialized, and $route.current is correctly set), to be sure to catch the first routing handling. This listener will do three things:

  • Remove itself
  • Add a listener (routeChangeStartHandler) on $routeChangeStart
  • manually call trigger the routeChange events to act on the current route.

Note that using $routeProvider.otherwise() is not really an option because I wan to be able to restrict some routes depending on user rights, and implement all this logic in a centralized location (i.e. the main controller)

Which versions of AngularJS, and which browser / OS are affected by this issue? Did this work in previous versions of AngularJS? Please also test with the latest stable and snapshot (https://code.angularjs.org/snapshot/) versions.

Angular v1.6.2

Other information (e.g. stacktraces, related issues, suggestions how to fix)

@gkalpak
Copy link
Member

gkalpak commented Feb 10, 2017

This seems to have been intentionally introduced five years ago in 9486590, where firing event even if not route has changed was mentioned as a problem of the then current implementation:

Problems:
[...]
route fires after/before route change even if there is no route (when no otherwise specified)

It even introduced a test to specifically verify that no event is fired on bootstrap: here
This test lives happily in the codebase ever after: still here

Generally, I think it makes sense that no events are triggered when there is no "change". One might argue that for the bootstrapping specifically, there should be a change event fired (I am not sure how I feel about it).

That said, if what you want it to detect cases where there is no associated $route for a location change (because that would be an programmatic error for example), it is easy to achieve (as you have already figured out) by listening to $locationChangeSuccess events and checking for $route.current.

This makes perfect sense imo, as it reflects exactly what you are doing:

If - after the location has (succesfully) changed - there is no current route, we have a problem

$rootScope.$on('$locationChangeSuccess', function () {
  if (!$route.current) {
    // Houston, we have a problem!
  }
});

Here is a demo that shows this in action.

I am going to close this, because:

  1. The current behavior seems to be by design.
  2. Your usecase is still supported.
  3. Changing the implementation now would be a breaking change (and I don't see any real benefit - e.g. no new usecases supported).

Feel free to continue the discussion below (and point out anything I might have missed).
(Also, if you feel that a documentation update would be helpful, we happily accept PRs 😉)

@matthieusieben
Copy link
Author

matthieusieben commented Feb 10, 2017

Allright, I'm just gonna keep my workaround. Just wanted to make sure this was by design.

It might be worth mentioning in the doc that, unlike $locationChange* events, $routeChange* events won't be triggered during bootstrap if no route matches the initial path though. Had to read the code to figure that out 😆

Thanks for the fast reply!
Cheers

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants