4

I'm making an app using the angular ui router.

When navigating to a particular state, which always has parameters passed to it, I need to be able to change the url and update the parameters without reloading the view.

In my state config I'm using: reloadOnSearch: false

This works and allows me to update the parameters in the URL without page reload.

However, I need to be notified of these changes on the $stateParams so I can run various methods that will do things with the new data.

Any suggestions?

Thanks, James

jameslouiz
  • 396
  • 4
  • 12

2 Answers2

4

This is relevant to me so I did a bit of work.

Here is my state that uses reloadOnSearch but fires off a function each time the URL is updated.

      .state('route2.list', {
          url: "/list/:listId",
          templateUrl: "route2.list.html",
          reloadOnSearch: false,
          controller: function($scope, $stateParams){
            console.log($stateParams);
            $scope.listId = $stateParams.listId;
            $scope.things = ["A", "Set", "Of", "Things"];
            //This will fire off every time you update the URL.
            $scope.$on('$locationChangeSuccess', function(event) { 
                $scope.listId = 22;
                console.log("Update");
                console.log($location.url()); 
                console.log($stateParams);    
                });
          }
      }

Returns in console:

Update
/route2/list/7 (index):70
Object {listId: "8"} (index):71

$locationChangeStart and $locationChangeSuccess should get you where you want to go. Keep in mind that your location functions will always fire off, even on the first load.

Inspiration taken from this SO post and the $location documentation

EDIT 2 According to the Angular docs for ngRoute, $routeParams aren't updated until after the success of the changes. Chances are that ui-route has a similar restriction. Since we're inturrupting the resolution of the state, $stateParams is never updated. What you can do is just emulate how $stateParams are passed in the first place using $urlMatcherFactory.

Like so:

      .state('route2.list', {
          url: "/list/:listId",
          templateUrl: "route2.list.html",
          reloadOnSearch: false,
          controller: function($scope, $stateParams, $state, $urlMatcherFactory){
            console.log($stateParams.listId + " :: " + $location.url());
            $scope.listId = $stateParams.listId;
            $scope.things = ["A", "Set", "Of", "Things"];
            $scope.$on('$locationChangeSuccess', function(event) { 
                $scope.listId = 22;
                //For when you want to dynamically assign arguments for .compile
                console.log($state.get($state.current).url); //returns /list/:listId
                //plain text for the argument for clarity
                var urlMatcher = $urlMatcherFactory.compile("/route2/list/:listId");
                //below returns Object {listId: "11" when url is "/list/11"} 
                console.log(urlMatcher.exec($location.url())); 
                var matched = urlMatcher.exec($location.url());
                //this line will be wrong unless we set $stateParams = matched
                console.log("Update " + $stateParams.listId);
                console.log($location.url());
                //properly updates scope.
                $scope.listId = matched.listId;
                });
          }
      })

The scope actually updates, so that's a good thing. The thing to remember is that you're stoppng the normal resolution of everything but setting reloadOnSearch to false so you'll need to handle pretty much everything on your own.

Community
  • 1
  • 1
Roman K.
  • 164
  • 5
  • Hi, thanks for taking time to help me.. This is certainly a step in the right direction. So now I have an event to play with, how can i get the new parameters after change? $stateParams isnt updated – jameslouiz Jul 26 '14 at 16:33
  • Location is still available to you if you pass it in. You can get the route using its functions, or something similar. Note the by using `$locationChangeStart` and `reloadOnSearch` you're pretty much stopping any scope updates. `$scope.$apply()` will likely be your friend with this as well. Also, you need to use `$locationChangeSuccess` if you want the final URL. – Roman K. Jul 26 '14 at 16:55
  • Yes i understand that, but i need to return an object like the $stateParams obj. Doesn't angular-ui have some sort of method that actually gets the stateparams? – jameslouiz Jul 26 '14 at 17:07
  • Edit 2 is up. Even if someone comes along with a one line way to do this, I learned quite a bit about how ui-router works. – Roman K. Jul 26 '14 at 18:31
  • Roman! Thanks so much this is exactly what I'm looking for! I'll put this in a service :) – jameslouiz Jul 27 '14 at 13:19
1

Following on from Romans code, i built a service that returns the state params of of the current state

/**
 * Get parameters from URL and return them as an object like in ui-router
 */
eventaApp.service( 'getStateParams', ['$urlMatcherFactory', '$location', '$state', function(     $urlMatcherFactory, $location, $state ){
  return function() {

    var urlMatcher = $urlMatcherFactory.compile($state.current.url);
    return urlMatcher.exec($location.url());

  }

}]);
jameslouiz
  • 396
  • 4
  • 12