Christian THC
Christian THC

Reputation: 193

Angular: mixing ng-repeat, arrays, and objects with ids

I have a collection of items which I'm using with ng-repeat and filtering.

Each item has a unique Id, and is stored in an array:

[ {id: 387, name: "hello"}, {id: 2878, name: "world"}, ...]

But now I need to reference these objects by their unique id instead of array index (as well as use ng-repeat with filters).

So I tried using a sparse array:

array[387] = {name: "hello"}; array[2878] = {name: "world"}...

But ng-repeat craps itself because it sees 'duplicate' undefined keys. (I also tried using 'track by' but ng-repeat still didn't like it).

I can't use an object with ng-repeat because filters don't work.

Soooo, how can I both use ng-repeat with filters, and be able to reference the items by id? The only option I can think of is to have a second data structure to map id's to indexes.

Thanks for your help!

Chris.

Upvotes: 0

Views: 884

Answers (3)

Alagarasan M
Alagarasan M

Reputation: 907

Try this:

'track by $index'

ng-repeat="name in Lists track by $index"

Upvotes: 1

wayne
wayne

Reputation: 3410

I can see your ids are integer. angular filters not working because angular use string comparison for number.

Go to the angular.js search a function name filterFilter. line 13991 for v1.2.10. Then you can use objects in your ng-repeat.

function filterFilter() {
  ...

  var search = function(obj, text){
  if (typeof text == 'string' && text.charAt(0) === '!') {
    return !search(obj, text.substr(1));
  }
  switch (typeof obj) {
    case "boolean":
    case "number": // <-- here
                   // add return obj === text;
    case "string":
      return comparator(obj, text);
    case "object":
      switch (typeof text) {
        case "object":
          return comparator(obj, text);
        default:
          for ( var objKey in obj) {
            if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
              return true;
            }
          }
          break;
      }
      return false;
    case "array":
      for ( var i = 0; i < obj.length; i++) {
        if (search(obj[i], text)) {
          return true;
        }
      }
      return false;
    default:
      return false;
  }
};

Upvotes: 0

Matt Way
Matt Way

Reputation: 33179

When I need to achieve this sort of thing, I do some quick preprocessing of the data grabbed, and create the necessary lookup. For example:

var data = [
    { id: 55, name: 'some name' },
    { id: 65, name: 'another name' }
];

// create a lookup
var lookup = {};
angular.forEach(data, function(item){
    lookup[data.id] = item;        
});

You could manipulate the data any way you want here, but by referencing the actual array items, you can bind either the data or lookup (or both) to $scope, and any changes will be exhibited on both structures. Bear in mind this won't happen if you add/remove items from the array, as you need to manage the addition and removal of items from the lookup.

Upvotes: 0

Related Questions