7

I have my app set up where a list of products can be filtered by colour using a select input, I also have the $routeprovider passing this colour param to the page if it is present in the url.

What I want to do now is update the url / route when the select box is changed. How do I bind the change of the select to the route?

sudo bangbang
  • 27,127
  • 11
  • 75
  • 77
Tim Webster
  • 9,158
  • 8
  • 27
  • 30

2 Answers2

12

select has an undocumented ng-change parameter that you can use to call a function to set $location.path:

<select ... ng-model="color" ng-change="updatePath()">

Controller:

function MyCtrl($scope, $location) {
    $scope.updatePath = function() {
       $location.path(... use $scope.color here ...);
    }
}
Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • Works like a charm, although for some reason the select box then reverts to having nothing selected rather than the chosen colour> – Tim Webster Feb 06 '13 at 16:00
  • In your controller, set $scope.color to the color parameter from the route. Note that if you are using an array of objects to generate your select list, you'll need to set $scope.color to point to an element of that array. See [this post](http://stackoverflow.com/questions/14297560/how-to-make-a-preselection-for-a-select-list-generated-by-angularjs) for more info. – Mark Rajcok Feb 06 '13 at 16:15
  • I am using the product array to populate the select list, but am also using this (underscore) to pull unique colour titles from that array `code` $scope.uniqueColours = function() { return _.chain($scope.products) .pluck('colour_title') .flatten() .unique() .value(); }; `code` so it no longer reflects the initial product array. s it not possible to set $scope.by_colour = $routeParams.colour_title; – Tim Webster Feb 06 '13 at 16:41
  • 1
    The way select and ng-options work, you have to initialize your ng-model to an element of the array used in ng-options. So in your controller, you'll need to loop through your array and find the appropriate element, then set $scope.by_colour to that. – Mark Rajcok Feb 06 '13 at 17:15
  • Thanks again @Mark Rajcok, I've marked the response above as correct as it answers my original query. I was initially using ng-repeat to build my options rather than ng-options, which leads to another question but not really relevant in this thread. – Tim Webster Feb 07 '13 at 09:56
4

Your <select> element will be bound to a model with ng-model, which you can $watch and use to update either $location.path or $location.search. Personally, I'd suggest using $location.search: you can change just the parameter you want, and its a bit less work since you don't have to have knowledge of the entire path in your controller.

So assuming you have a <select> element like this:

<select ng-model="selectedColor" ng-options="color for color in colors">

You can use $watch to watch your bound value and update your $location.search, making sure to set it to null if color is undefined or otherwise falsey (this clears the search parameter):

$scope.$watch('selectedColor', function (color) {
    if (color) {
      $location.search('color', color); 
    } else {
      $location.search('color', null);
    }
});

You might want to set up a two-way binding between the search parameter and your local model so that changes will be reflected in your <select>:

$scope.$watch('$location.search().color', function (color) {
    $scope.selectedColor = color;
});

Then it's just a matter of accessing $routeParams.color in your routed controller.

See this plunk for a complete working example.

Scott Baldwin
  • 422
  • 3
  • 9