AngularJS filter array by another array

Problem

I'm working on an Ionic hybrid app, but I'm quite new in Javascript / AngularJS.

I have this data structure:

  var objects= [
    {
      name: "o1",
      company: {
        id:2,
        fields: [1,6]
      }
    },
    {
      name: "o2",
      company: {
        id:2,
        fields: [3,4,5]
      }
    }
  ];

  var selectedFields= [
    {
      id: 1,
      name: "f1",
    },
    {
      id: 2,
      name: "f2",
    }
  ];

I want to filter the objects array elements which contains the ids (in the attribute company.fields) corresponding with the elements contained in selectedFields array.

For example, in this case, we have 2 elements, o1 and o2. o1 contains the fields 1 and 6, and o2 contains the fields 3, 4 and 5. The selectedFields array contains the fields with ids 1 and 2, so in this case the filtered object should be the object o1.

That's what I have tried:

var filteredObjects = filterFilter(objects, selectedFields,function(o, sf){
      return angular.forEach(o.company.fields, function (field) {
        return field.id == sf.is;
      });
});

But it says that o is undefined.

and:

var result = [];
  angular.forEach(objects, function(o){
    angular.forEach(o.company.fields, function(f){
      angular.forEach(selectedFields, function(sf){
        if(sf.id == f.id) {
          result.push(o);
        }
      });
    });
  });

But the condition if(sf.id == f.id) is never true.

Any ideas? Thanks

Problem courtesy of: Ale

Solution

Try this:

var test = objects.filter(function (o) {
    return selectedFields.some(function (i) {
        /*
            Some will return true if any of the elements return true
        */
        return i.id === o.company.id; 
    });
});

Essentially were filtering the Object array. .Filter() will create a new array with elements from the old one if its callback returns true. What .some() will do is return true if any any of its callbacks return true.

So .some() returns true if the id's match, which is passed into .filter() telling filter to add that element to the new array.

.some() is efficient in that it will stop iterating if it finds a matching result, callback that returns true. Whilst .forEach() will keep going and won't return a value.

http://jsfiddle.net/08tvmdyh/

Some Docs: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/some

List of very usefully Array methods: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#Methods_2


EDIT: I misread your question sorry.

var test = objects.filter(function (o) {
    return selectedFields.some(function (i) {
        /*
            Some will return true if any of the elements return true
        */
        return o.company.fields.indexOf(i.id) !== -1; //i.id === o.company.id; 
    });
});

Ive modified the fiddle: http://jsfiddle.net/08tvmdyh/1/

Solution courtesy of: ste2425

Discussion

try this :

    var filteredObjects = objects.filter(function(o){

        var fields = o.company.fields,
            matched = false;

        selectedFields.forEach(function(field){
          if(fields.indexOf(field.id) != -1){
            matched = true;
          }
        });

        return matched;
     });

First try to understand the following 3 native Array Functions built in Javascript :

    Array.prototype.filter;
    Array.prototype.forEach;
    Array.prototype.indexOf;
Discussion courtesy of: Chuan

This recipe can be found in it's original form on Stack Over Flow.