angular-ui / ui-router

The de-facto solution to flexible routing with nested views in AngularJS
http://ui-router.github.io/
MIT License
13.53k stars 3k forks source link

Behaviour of $state.reload() differs from angular's $route.reload() #544

Closed smashercosmo closed 10 years ago

smashercosmo commented 10 years ago

Here are two plunkers that show the difference: $state.reload - http://plnkr.co/edit/OpZ71z $route.reload - http://plnkr.co/edit/j3VFPw

timkindberg commented 10 years ago

@nateabele I looked into this and have a good idea what the issue is.

So in his plunkr he's setting up a state with url "/" so the app tries to go there right away. He also has a $stateChangeStart listener which preventDefaults the transitions (canceling it). But there's also a $timeout which will attempt to reload the state. Problem is that by preventing the state, you are essentially remaining in the previous state; the root state. The root state is abstract, and therefore when it reloads it errors because you can't transitionTo an abstract state.

Maybe $route does not kick back to previous "route" after a preventDefault and that's why it works?

Either way I'm not sure we can consider this a bug, because its as we designed it:

smashercosmo commented 10 years ago

@timkindberg not '$stateChangeStart', but '$locationChangeStart'. The thing is that angular router can somehow reload route even if it didn't load it. May be it analizes location url and defines what route it should reload.

timkindberg commented 10 years ago

Ah ok, I had "fixed" the plunkr to use $stateChangeStart thinking you just forgot to swap it out. Also your plunkr was still using ng-view instead of ui-view. Lastly to get the index state to activate upon site load, the url needs to be empty (that's how it worked for me anyway). Using "" instead of "/".

Is there still a bug here @smashercosmo? What are you wanting?

timkindberg commented 10 years ago

Fixed plunkr, also commented out the stuff in the listener condition, so you can see the template loading properly. Uncomment to see the errors, which aren't necessarily bugs.

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

smashercosmo commented 10 years ago

What I want is to be able to prevent state loading and then (after timeout or ajax request) reload the state, which was prevented to load. This is possible and easy to implement with angular native router (as you can see from this plunkr http://plnkr.co/edit/j3VFPw). Real live example: I load my app, but before any route (or state) loads I want to send authorization token to the server and (depend on response) either reload this route or redirect to login page.

timkindberg commented 10 years ago

Can you just use $state.go(toState, toParams) instead of reload?

nateabele commented 10 years ago

API compatibility with an existing primitive and highly constraining system is not a virtue. Modeling an application with states is drastically different from simply writing a few routes up to controllers. With such fundamental conceptual differences, it's natural and expected that not all problems will be solved the same way, or with identical outcomes.

That said, this library provides you with a much more powerful and complex set of tools with which to solve your problems when compared to ngRoute, but don't expect code from the one to map identically to the other. Sorry if you were under the impression that that was a goal.

smashercosmo commented 10 years ago

@timkindberg nope, I can't, because I don't know what state user is going to load.

smashercosmo commented 10 years ago

@nateabele I'm not expecting the exact code mapping) I just need an opportunity to define which state user is going to load before he actually loads it. May be I should open another issue as a feature request. What do you think?

smashercosmo commented 10 years ago

I've just looked through angular router source and found out that my guess was right. It actually iterates through all routes and defines current route by simple regexp matching. I really can't understand why ui-router can't implement the same behaviour. I can provide a PR if this idea is acceptable.

smashercosmo commented 10 years ago

Ok. If someone also need this functionality and it won't be implemented by ui-router community, here is a quick solution:

$state.reload = function() {
    var matchedState = null,
         matchedStateParams = null;

    angular.forEach($state.get(), function(state) {
        var url = state.url ? $urlMatcherFactory.compile(state.url) : null,
             params = url ? url.exec($location.path(), $location.search()) : null;

        if (!matchedState && params) {
            matchedState = state;
            matchedStateParams = params;
        }
    });
    $state.transitionTo(matchedState,  matchedStateParams, { reload: true });
};
timkindberg commented 10 years ago

@smashercosmo I thought you could know the state they are going to by using the toState param that is passed to the event handler.

smashercosmo commented 10 years ago

@timkindberg nope, because I'm using $locationChangeStart event and not $stateChangeStart