Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parent state not resolving when transitioning from child #2520

Closed
jpodpro opened this issue Feb 4, 2016 · 6 comments
Closed

Parent state not resolving when transitioning from child #2520

jpodpro opened this issue Feb 4, 2016 · 6 comments

Comments

@jpodpro
Copy link

jpodpro commented Feb 4, 2016

i have a resolve in my parent state and a resolve in each child state. the resolves all fire properly until i transition from a child state to the parent state. in this situation the resolve is not run and the data i expect from the resolve is null.

i couldn't figure out if this is expected behavior as nothing in the documentation seems to imply this behavior. if this is expected behavior, am i required to abandon the resolve system in order to get the data i need? hooks are an option but it seems strange to have to create a hook for this one special case.

@jpodpro jpodpro changed the title 1.0 frustrations. hooks. $transitionsProvider. _ Feb 4, 2016
@jpodpro jpodpro closed this as completed Feb 4, 2016
@jpodpro jpodpro changed the title _ Parent state not resolving when transitioning from child Feb 4, 2016
@jpodpro jpodpro reopened this Feb 4, 2016
@nateabele
Copy link
Contributor

This is in 1.0? Please post a plunkr that demonstrates the issue.

@christopherthielen
Copy link
Contributor

transition from a child state to the parent state. in this situation the resolve is not run and the data i expect from the resolve is null.

When transitioning from child to parent, the parent is "retained"; it is neither exited nor re-entered. Resolves (and views) are triggered when a state is entered.

See the sample application: http://ui-router.github.io/sample-app/#/mymessages/personal

When we transition from contacts state to mymessages.folder (transition #22) the parent state app is retained (neither exited nor entered).

When we transition from mymessages.folder({ folder: "inbox" }) to mymessages.folder({ folder: "personal" }), only mymessages.folder is exited and re-entered (because the parameter changed). the mymessages parent state is retained.
When we then transition fr
screen shot 2016-02-04 at 10 25 28 am

If you want to reload the state, you can specify `{reload: 'mymessages'}, and the state will be forcibly exited/re-entered

This can be seen in the contacts.contact.edit state, where the save() method saves the contact to the server, then transitions back to the parent state, while forcing a reload.

https://github.com/ui-router/sample-app/blob/master/app/contacts/editContact.component.js#L44-L49

@jpodpro
Copy link
Author

jpodpro commented Feb 4, 2016

thanks for the detailed info.

however my case is using ng-href to transition between states. basically i have a profile menu with sub-menu items. the top-level menu items are sub-states of the profile (profilePage.activity, profilePage.tracks, etc). the sub-menu states are sub-states of one of the top level states ( profilePage.activity.upvotes, profilePage.activity.plays, etc). i prefer to use ng-href so that the status bar shows the actual href destination of selecting one of the menu items.

the problem is that any of the top level or sub menu items share their controller and all load data into the same view, since any one of the top or sub items is simply selecting the content to be shown below the menu. i can imagine that in a typical scenario, the parent data wouldn't be changing when navigating from a sub state to its parent. but in my case a child state overrides the parent data because only one state is shown at a time, top or sub.

i was thinking of changing this from parent states to sibling states because obviously that would fix everything. but doing this means that i don't get the url hierarchy i wanted: ( /activity/plays ). i was sure that with 1.0 there would be a way to achieve what i want but it doesn't seem obvious.

below is a subset of my state definition code. if i'm in the profilePage.activity.plays state and i navigate in the menu to the profilePage.activity state, the resolve is not loaded and contentData is null. it seems like my options are as follows:

  • change to sibling states, sacrifice desired url hierarchy
  • use ng-click and $state.go to force reload as described above, sacrifice visible url in status bar
  • use separate resolve names, capture and save the parent data when it is loaded, capture state change using hook and use saved data to load. ugh.

if this isn't enough info i can try to make a plunkr...

// top level profile state works fine
$stateProvider.state( 'profilePage', {
    url: '/u/:user',
    templateUrl: 'app/user/profilePage/profilePage.html',
    controller: 'ProfileController',
    controllerAs: 'pc',
    resolve: {
        profileData: ['profileService', '$stateParams', function( profileService, $stateParams )
        {
            profileService.init( $stateParams.user );
            return profileService.getProfile();
        }]
    }
});

// this state is not resolved when transitioning from sub-state
$stateProvider.state( 'profilePage.activity', {
    url: '/activity',
    templateUrl: 'app/user/profilePage/profilePage.tracks.html',
    controller: 'ProfileContentController',
    controllerAs: 'pcc',
    resolve: {
        contentData: ['profileService', '$transition$', function( profileService, $transition$ )
        {
            return profileService.loadState( $transition$.to().name, 0 );
        }]
    }
});

// sub state always resolves
$stateProvider.state( 'profilePage.activity.plays', {
    url: '/plays',
    templateUrl: 'app/user/profilePage/profilePage.activity.plays.html',
    controller: 'ProfileContentController',
    controllerAs: 'pcc',
    resolve: {
        contentData: ['profileService', '$transition$', function( profileService, $transition$ )
        {
            return profileService.loadState( $transition$.to().name, 0 );
        }]
    }
});

@christopherthielen
Copy link
Contributor

Show me a representative plunker. I'd like to see what data is being loaded, and where you would like it to be used. I feel like you're misusing the hierarchical state system a bit and want to be able to point out an alternative.

If you are simply selecting which content the parent state should be using, that sounds like a state parameter.

I also highly recommend you use ui-sref over ng-href. ui-sref applies the 'href' attribute automatically to anchor tags ()

@jpodpro
Copy link
Author

jpodpro commented Feb 7, 2016

here is a plunker showing a simplified scenario. ideally, any of the menu items would trigger their resolve only when selected. currently 'activity' is resolved in one of two scenarios: when selecting the sub-menu item 'plays' or when transitioning to 'activity' from 'plays'. selecting 'plays' results in two resolves and two content requests - not ideal with real data. another option would be to abandon resolves and simply request the data in the controller as it is always loaded only once. i thought using resolve was a prettier solution but it doesn't seem trivial to force resolving to happen exactly when i want it to.

re: ui-sref - i'm using a data-driven menu which is sortable and ui-sref can't take a binding that changes so i was forced to use ng-href="{{ $state.href( menuItem.item.state ) }} instead of ui-sref={{ menuItem.item.state }}

https://plnkr.co/edit/jGnv6ZXSb1FKhSMnPPyI?p=preview

@jpodpro
Copy link
Author

jpodpro commented Feb 7, 2016

since i understand that parent and child resolves work in a particular way, i've decided to abandon the use of resolves for my profile page child states and simply load the content data in the controller. while this solution annoys my desire for consistency it works as required so i'm reasonably satisfied.

i understand why things work the way they do - however, since views can be absolutely targeted i would have expected some ability to configure custom nested state behavior. for example it would be convenient to specify a state should always resolve when it is transitioned and not only in the current cases. it would also be handy to easily prevent parent states from resolving when child states are loaded.

@jpodpro jpodpro closed this as completed Feb 7, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants