5

I am using ng-repeat to display my data. That is working fine.

One of the data fields in my ng-repeat result set is an array of items. Example: {x:1, y:[2,3,4]} I would like to filter by data by data in the array. I can easily filter by the non array data, but I am having trouble when I try to filer by looking inisde in the array.

Here is my markup ng-repeat = "con in cons | filter: usrSingle.username in con.conPlayerList"

(edited markup to match my example better ng-repeat = "con in cons | filter: '3' in con.y" )

usrSingle is a scope in this controller I can access. I don't get any errors and I can't seem to find examples of this.

More code was requested and here it is below. I forgot to mention this is a MEAN app. I have MongoDB serving the data. I use a REST API for my data calls.

(EDIT) code from the angular module:

// call to the api for data
app.factory('usrService', function ($resource) {
return $resource('/api/users', {});
});
// factory to hold user data between controllers
app.factory('usrTracker', function () {
var vUsrProfile = {
    usrSingle: 'usrSingle'
};
return {
    getProperty: function () {
        return vUsrProfile;
    },
    setProperty: function (value) {
        vUsrProfile = value;
    }
};
});
// angular controller
app.controller('usrPageController', function ($scope, usrTracker, conService, postService) {

var usrSingle = usrTracker.getProperty();
$scope.usrSingle = usrSingle;
$scope.cons = conService.query();
$scope.posts = postService.query();
});

(FINAL EDIT) The answer marked for this is a good solution. But I went another direction. I used the mongoDB $unwind aggregation to explode my data, like below.

code from API file:

// get
.get(function (req, res) {
// unwind on the conPlayerList array field
Con.aggregate([{ $unwind: "$conPlayerList" }], function (err, cons) {
return res.json(cons);
});
})

Then I filtered on the user I was looking for. Changing the HTML Angular markup to this

ng-repeat="con in cons | filter:{conPlayerList:usrSingle.username}"

to match my example better, by removing my specific code, it would be:

ng-repeat="con in cons | filter: {y:'3'} "

5
  • 1
    You are probably better off writing your own filter function. Consider using a helper library such as lodash (underscore). Commented Oct 30, 2015 at 23:38
  • Can you please provide more code so it becomes easy to come up with different solutions to your problem. You might not need to use filters at all. Commented Oct 30, 2015 at 23:51
  • I think this needs its own separate filter. I can do that but I was wondering if there was a way to look inside an array that is returned by the ng-repeat command. It seems highly likely that data in a ng-repeat would have fields that are arrays. Commented Oct 31, 2015 at 0:28
  • there is no view syntax that will do this without a filter function Commented Oct 31, 2015 at 0:36
  • I am new to Angular so I want to make sure I am not missing something simple. The filter functions are a great option for dealing with these types of problems Commented Oct 31, 2015 at 1:24

1 Answer 1

4

You can use Angular's built in filter logic on the array, BUT bear in mind this is not an exact match and will match against an array entry of 300 if usrSingle is set to 3, see example in Fiddle.

<div ng-repeat = "con in cons | filter:{y:usrSingle} ">...</div> 

To match exactly against array elements you can use filter: and a predicate function on the controller i.e.

Controller (Fiddle):

app.controller('usrPageController', function ($scope) {
  $scope.filterFn = filterFn;
  $scope.usrSingle = 3;
  $scope.cons = [
      {x:0, y:[1,2,3]},
      {x:1, y:[2,3,4]},
      {x:2, y:[3,4,5]},
      {x:3, y:[4,5,6]},
      {x:4, y:[5,6,7]}
  ];

  function filterFn(con){
    return con.y.indexOf($scope.usrSingle) > -1;
  }
});

View:

<div ng-repeat = "con in cons | filter:filterFn">...</div>

Alternatively you can create a custom filter which can be reused elsewhere in your app and pass usrSingle in as a parameter:

Filter (Fiddle):

app.filter('customFilter', function() {
  return function(input, value) {
    var result = [];
    input.forEach(function(item){
        if(item.y.indexOf(value) > -1){
            result.push(item);
        }
    });
    return result;
  };
});

View:

<div ng-repeat = "con in cons | customFilter:usrSingle">...</div>
Sign up to request clarification or add additional context in comments.

3 Comments

This is a great workaround but not the answer I am looking for. It sounds like the only way to filter at point is to use a custom function. I tested your function with my code and the controller function worked great. I will stick with my MongoDB unwind for the moment but I appreciate your answer and detail. Thank you.
You're welcome! Ah I understand better your question - updated answer with an additional example you might find useful.
@sheilak can you help me with this

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.