David Wolever
David Wolever

Reputation: 154454

Refresh ui-router view when state parameters change?

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.

Upvotes: 7

Views: 9052

Answers (3)

joeforker
joeforker

Reputation: 41747

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.

Upvotes: 1

Radim Köhler
Radim Köhler

Reputation: 123861

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

Upvotes: 2

Myk
Myk

Reputation: 6215

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.

Upvotes: 10

Related Questions