0

If I leave the sort order unchanged, using routeParams.id to pull the correct object from my scope.data object works like a charm. As soon as the order changes, the routeParams.id changes and doesn't match up with the order of objects within $scope.data.

$scope.cars = {
  [ {"make":"koenigsegg", "model":"agera"}, { "make":"pagani", "model":"huayra"},
   {"make":noble, "model":"m600"}, {"make":"bugatti", "model":"veyron"} ]
}

// car list page
<li ng-repeat="(id, car) in cars">
  <a href="#/{{id}}>{{car.model}}</a>
</li>

// Get data for individual car based on URL
// This is the key piece I'm having trouble with
controller.myCtrl = function($scope, $routeParams) {
  $scope.car = $scope.cars[$routeParams.id];
};

// specific car page
<p>{{car.make}}: {{car.model}}</p>

So clicking "Agera" with id 0 will open /#/0 and the binding will correspond to $scope.cars[0], showing the data for the Agera. But if the sort order changes to say, "make", putting the Bugatti first, now if you click the "Veyron" link an id of 0 will again be passed but since the data object hasn't changed the 0 still maps to the "Agera."

Ideally, I'd like to just use my own $routeParams so that the URL is more explicit:

$routeProvider.when('/:make/:model, { ... });

<a href="#/{{car.make}}/{{car.model}}">{{car.model}}</a>

But now I have no way of telling my data array which car object to use. So how do I use $routeParams to connect to the correct "car" object in my cars array without using the array order id?

Or how can I keep the ids fixed to their objects so that they aren't attached to the sort order?

== Edit ==

Ok, I've changed my scope to explicitly call out each item in the object:

$scope.car = { make: routeParams.make, model: routeParams.model, ... };

So that works. Seems horribly inefficient though for big objects. Plus it doesn't work if that data isn't in the URL. Is there a better way?

iamsar
  • 1,080
  • 2
  • 15
  • 28

1 Answers1

1

So basically you need to key off of something in this case the key is the make and model so you'll have to work through your array to find the proper keyed item.

Example (working plunk at http://plnkr.co/edit/9zCqsyWomYeTgm3GJTsv?p=preview):

var app = angular.module('plunker', []).config(function($routeProvider){
    $routeProvider
      .when('/', {templateUrl: 'home.html'})
      .when('/:make/:model', {templateUrl: 'car.html'})
      .otherwise({redirectTo: '/'});

  }
);

app.controller('MainCtrl', function($scope) {
  $scope.cars = [ 
      {"make":"koenigsegg", "model":"agera"},
      {"make":"pagani", "model":"huayra"},
      {"make":"noble", "model":"m600"}, 
      {"make":"bugatti", "model":"veyron"} 
    ]
});

app.controller('CarCtrl', function($scope, $routeParams) {
  var findCar = function(){
    for(var i = 0; i < $scope.$parent.cars.length; ++i){
      var car = $scope.$parent.cars[i];
      if(car.make === $routeParams.make && car.model === $routeParams.model){
        return car;
      }
    }
  }
  $scope.car = findCar();

  $scope.$routeParams = $routeParams;
});

As far as getting this to be more efficient, you'll want to create a service to create some sort of index of your key so that then when you go to look it up you do so more quickly (instead of looping through the full array). You can see how to make a service at http://docs.angularjs.org/tutorial/step_11.

Paul Ryan
  • 1,509
  • 12
  • 26
  • Your looping example totally makes sense but you're right, not efficient. My actual data is already stored in a factory. Is there a way to run specific queries on a factory? The page you referenced uses the params property in the get request but in doing so loads entirely different json. Good way to go for big data sets. I wonder if there's a middle ground: Query a single factory data set. – iamsar May 30 '13 at 19:00
  • Yes you can query that single factory dataset by pulling it into both controllers and putting functions on that data set to call from the controllers. So inject `myFactory` then call `$scope.car = myFactory.findCar(key)`. – Paul Ryan May 30 '13 at 19:03