On the initial load of my application, why is the ui-router status not set?


When I go to my app at https://localhost/my-app/resources/index.html, I have logic to go to my self-defined default state. However when I want to go directly to a specific part of my app (i.e. https://localhost/my-app/resources/index.html#/orders/draft) the state is not getting set (nor is the template loaded into the ui-view directive). Once that initial load is done (with the default state set), then I can do direct urls to my hearts content.

I think I'm missing some basic concept in how things are loaded in my app, but I would expect that the state would get set since the url is defined in $location.url()

A snippet of my code to handle states on initial load:

    var navigationObjects = response.data,
        directUrl = $location.url(),
        stateName = null;

    scope.availableStates = ims360RouterStateService.getAvailableStates(navigationObjects);
    if (!directUrl)
        //TODO there's probably a better way to do this
        //parsing out the state name, requires that the state name matches the url, this fails when I have a place holder (such as an id to a resource)
        stateName = directUrl.substring(1).replace(/\//g, ".");

In this code I get navigation objects from the server which determine which ui-router states the user has access to. All my defined states are then filtered down to the availableStates which are what I use for my navigation ui.

Additionally, the "updatePrimaryState(...) includes a call to $state.go(...)

So, why is the state not set on initial load? And if that IS expected behavior, then what is a good way to direct the user to the url specified?


I created a plunker that shows the expected behavior (http://plnkr.co/edit/m9gQLOZmqaAY88wSc6wC?p=preview). I tried to duplicate my issue, but in the simple case it just works as expected. So obviously there is something on my end that is incorrect, but my setup is very similar to that in the plunker. To test the scenario I am seeing in my app you'd need to:

  1. launch the plunker view in a separate window
  2. After verifying that the state is set, copy and paste the link into a new window.
  3. In this new window, the app should go directly to the state that matches the url. In the plunker this works, but in my app, it does not.

After my app is loaded, the state loaded is the empty state named: "" with the url "^".

UPDATE 2 After digging into the code looking for the difference, I found that when the angular "$locationChangeSuccess" is broadcast, the listener in ui-router is not initialized yet. I'm finding the difference is that we have a separate (reusable) login app that is bootstrapped initially, which then upon successful login, bootstraps the actual app. At the time the actual app is bootstrapped, the $locationChangeSuccess has already been broadcast and the ui-router listener isn't initialized yet to catch it.

My thought has been to rebroadcast the event after my app is bootstrapped, but I'm still having timing issues where the event listener is seemingly the last thing initialized. I first added it to a myApp.run() block, but the broadcast was still happening beforehand. Putting the broadcast into the app's main directive's link function (where the ui-view is) works, but not sure this is a good approach. Is there a better way?

I've just found this http://niclassahlin.com/2014/05/31/kickstarting-angular-ui-router/ and it works like charm for me.

With the next code in your app.js you could achieve the initial state:

app.run(['$state', function ($state) {}])