7

What's the correct way to update a ui-router view when state parameters change?

For example, if I've got a state like:

.state("page.view", { url: "/pages/:slug", views: { "": { controller: "PageCtrl", templateUrl: "page-view.html", }, }, }) 

And an (incorrect) controller which looks like this:

.controller("PageCtrl", function($scope, $state) { $scope.page = loadPageFromSlug($state.params.slug); }) 

How can I correctly load a new $scope.page when the $state.slug changes?

Note that the above does not work when moving from page to another because the controller is only run once, when the first page loads.

0

3 Answers 3

10

I would do something like this:

.controller("PageCtrl", function($scope, $state) { $scope.$on("$stateChangeSuccess", function updatePage() { $scope.page = $state.params.slug; }); }); 

I'd be curious if you find a better way - there may be some way to just watch the value of the state slug, but this is clean and clearly articulates what it is that you're watching for.

Sign up to request clarification or add additional context in comments.

3 Comments

This… would definitely work. But… damn, it feels like a bit of a heavyweight solution for what I would assume — possibly naively? — to be an exceptionally common problem.
It's not at all heavyweight, though - you're listening to a simple event, that's already being fired. It's about the lightest weight solution to this problem I can think of. $scope.$watch with a function is adding a lot more overhead, I would think.
Err, sorry, I mean heavyweight in terms of "it feels like a weird solution to what should be a common problem"?
2

I am really not fully sure, if I do not miss something here - but, based on the snippets shown in your question:

  • PageCtrl is related to state "page.view" and will be run as many times as "page.view" state is triggered
  • "page.view" state has declared param slug - url: "/pages/:slug",, which will trigger state change - whenever it is changed
  • If the above is true (if I do not oversee something) we can use stateConfig setting - resolve
  • there is no need to use $state.params. We can use $stateParams (more UI-Router way I'd personally say)

Well if all that is correct, as shown in this working plunker, we can do it like this

resolver:

var slugResolver = ['$stateParams', '$http' , function resolveSlug($stateParams, $http){ return $http .get("slugs.json") .then(function(response){ var index = $stateParams.slug; return response.data[index]; }); }]; 

Adjusted state def:

.state("page.view", { url: "/pages/:slug", views: { "": { controller: "PageCtrl", templateUrl: "page-view.html", resolve: { slug : slugResolver }, }, }, }) 

And the PageCtrl:

.controller('PageCtrl', function($scope,slug) { $scope.slug = slug; }) 

Check it all in action here

1 Comment

While this seems the correct way to do it, it does not work when you use the same controller in some directive. :(
1

I had this problem in ui-router 0.2.14. After upgrading to 0.2.18 a parameter change does fire the expected $stateChange* events.

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.