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!

4 Answers 4

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'}); 
Sign up to request clarification or add additional context in comments.

4 Comments

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' }) '
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.
If I use this method the child state is reloaded, but it is reloaded twice?
Have you compared your setting with my plunker? is it same? or is there any difference? Maybe you should raise a question with more details
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

2 Comments

Is there a way to do this with ui-sref?
@AlxVallejo you can use ui-sref-opts for example: <a ui-sref="home" ui-sref-opts="{reload: 'home.child'}">Home</a>
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...

Comments

-1
$state.transitionTo("State Here", {"uniqueRequestCacheBuster": null}); 

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.