AngularJS UI Router $state reload child state only
Asked Answered
C

4

29

I am using UI router for tabs of a main menu as well as for links within one of the states (users). The users state has a list of users and when a user is clicked, I want to reload the child state only, but it is reloading both the child state and the parent state (users).

Here's my code:

    app.config(function ($stateProvider, $locationProvider, $urlRouterProvider) {
    $urlRouterProvider.otherwise("/");
    $locationProvider.html5Mode(true);
    $stateProvider
        .state('home', {
            abstract: true,
            template: '<div ui-view=""></div>',
            controller: 'HomeController as homeCtrl'
        })
        .state('users', {
            parent: 'home',
            url: '/users',
            templateUrl: '/User/Index',
            controller: 'UserController as userCtrl',
        })
        .state('users.createUser', {
            templateUrl: '/User/CreateUser',
            controller: 'CreateUserController as cuCtrl'
        })
        .state('users.editUser', {
            templateUrl: '/User/EditUser',
            controller: 'EditUserController as euCtrl',
            resolve: {
                userInfo: function (contextInfo, userData) {
                    return userData.get(contextInfo.getUserKey());
                }
            }
        })
        .state('users.addWebItemsForUser', {
            templateUrl: '/User/AddWebItemsForUser',
            controller: 'UserWebItemsController as uwiCtrl'
        })
        .state('users.addReportsForUser', {
            templateUrl: '/User/AddReportsForUser',
            controller: 'UserReportsController as urCtrl'
        })
        .state('users.userGroups', {
            templateUrl: '/User/UserGroups',
            controller: 'UserGroupController as userGroupCtrl'
        })
        //.state('users.logInWebApp', {
        //    template: '<h3>Logging into web app</h3>',
        //    resolve: {
        //        user: function() {
        //            return {
        //                //companyId: contextInfo.getCustomerKey()
        //                //userId:
        //                //password:
        //            }
        //        }
        //    },
        //    controller: function() {
        //        // need company code, username and password of user then need to open window with webapp url (will that work?) - do we still want to add this functionality?
        //    }
        //})
        .state('links', {
            url: '/links',
            templateUrl: '/Link/Index',
            controller: 'LinkController as linkCtrl'
        })
        .state('onlrpts', {
            url: '/onlineReports',
            templateUrl: '/OnlineReport/Index',
            controller: 'OnlineReportController as onlRptCtrl'
        })
        .state('reports', {
            url: '/customerReports',
            templateUrl: '/CustomerReport/Index',
            controller: 'CustomerReportController as custRptCtrl'
        });
})
.config(function($provide) {
    $provide.decorator('$state', function($delegate, $stateParams) {
        $delegate.forceReload = function() {
            return $delegate.go($delegate.$current.name, $stateParams, {
                reload: true,
                inherit: false,
                notify: true
            });
        };
        return $delegate;
    });
});

This is the function in my parent controller (UserController) that is called when a user is clicked:

            this.userTreeClick = function(e) {
        contextInfo.setUserKey(e.Key);
        contextInfo.setUserName(e.Value);
        userCtrl.userKey = e.Key;
        $state.forceReload();
    };

So say I was in the users.userGroups state, when I click on another user, I want only the users.userGroups state to be reloaded. Is this possible? I have looked for an answer via Google and here at StackOverflow, but I haven't found anything that is exactly like what I am trying to do. When I break to check the $state.$current.name - the name is correct - users.userGroups, but it reloads everything instead of just the child state. Any help is very much appreciated!

Cultivation answered 14/8, 2014 at 19:58 Comment(0)
V
30

As documented in API Reference , we can use $state.reload:

$state.reload(state)

A method that force reloads the current state. All resolves are re-resolved, controllers reinstantiated, and events re-fired.

Parameters:

  • state (optional)
    • A state name or a state object, which is the root of the resolves to be re-resolved.

An example:

//will reload 'contact.detail' and 'contact.detail.item' states
$state.reload('contact.detail');

Similar we can achieve with a $state.go() and its options parameter:

$state.go(to, params, options)

...

  • options (optional)
    • location ...
    • inherit ...
    • relative ...
    • notify ...
    • reload (v0.2.5) - {boolean=false|string|object}, If true will force transition even if no state or params have changed. It will reload the resolves and views of the current state and parent states. If reload is a string (or state object), the state object is fetched (by name, or object reference); and \ the transition reloads the resolves and views for that matched state, and all its children states.

Example from https://github.com/angular-ui/ui-router/issues/1612#issuecomment-77757224 by Chris T:

{ reload: true } // reloads all,
{ reload: 'foo.bar' } // reloads top.bar, and any children
{ reload: stateObj } // reloads state found in stateObj, and any children

An example

$state.go('contact', {...}, {reload: 'contact.detail'});
Vespid answered 15/8, 2014 at 7:36 Comment(4)
I thank you so much for your help. I tried to incorporate what you've shown here and the other entry, but it is not working. I am unable to see the plunker (I get plunk not found). I should have mentioned that I am using this in conjunction with MVC. The User/UserGroups go to a controller action which returns a partial view. ' .state('users.userGroups', { templateUrl: '/User/UserGroups/{userTrigger}', controller: 'UserGroupController as userGroupCtrl' }) 'Cultivation
Continued: Here is the controller code : ` this.userTreeClick = function(e) { contextInfo.setUserKey(e.Key); contextInfo.setUserName(e.Value); userCtrl.userKey = e.Key; var params = angular.copy($state.params); params.userTrigger = params.userTrigger === null ? "" : null; $state.transitionTo($state.current, params, { reload: false, inherit: true, notify: true }); }; Forgot to mention that now nothing is happening. The change is not reloading the state.Cultivation
If I use this method the child state is reloaded, but it is reloaded twice?Brainsick
Have you compared your setting with my plunker? is it same? or is there any difference? Maybe you should raise a question with more detailsZoilazoilla
B
28

The current ui-router (0.2.14 and above) added support to reload child state.

Simply put $state.go('your_state', params, {reload: 'child.state'}); will do the job.

See: https://github.com/angular-ui/ui-router/issues/1612 and https://github.com/angular-ui/ui-router/pull/1809/files

Bickerstaff answered 7/8, 2015 at 22:41 Comment(2)
Is there a way to do this with ui-sref?Picture
@Picture you can use ui-sref-opts for example: <a ui-sref="home" ui-sref-opts="{reload: 'home.child'}">Home</a>Utilize
C
1

I have gotten it to work. I used what Radim suggested, but I had to add the url element to the state.

.state('users.userGroups', {
    url: '/userGroups/{userTrigger}',
    templateUrl: '/User/UserGroups',
    controller: 'UserGroupController as userGroupCtrl'
})

and in my controller, when a user clickes on a link, I use the $state.transitionTo:

var params = angular.copy($state.params);
params.userTrigger = params.userTrigger === null ? "" : null;
$state.transitionTo($state.current, params, { reload: false, inherit: true, notify: true }); 

Just an FYI for any other newbies out there:

after I added the url to the .state, I started having issues with my api calls. It was prepending the urls to the api methods with the url in my .state. You just have to be sure to have a leading / in your api urls:

.factory('usersInGroup', function($http) {
    return {
        get: function(groupName) {
            return $http.get('/api/UserApi/GetInGroup/' + groupName);
        }
    }

I saw and learned some pretty interesting stuff trying to muddle through this...

Cultivation answered 15/8, 2014 at 21:4 Comment(0)
M
-1
$state.transitionTo("State Here", {"uniqueRequestCacheBuster": null});

This will simply reload only that child state as you wanted. not the whole hierarchy of states.

Mantinea answered 30/8, 2016 at 6:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.