1

I want to put this filter: filter:'!Category' on to this element like so:

<div ng-repeat="(prop, ignoredValue) in wines[0] | filter:'!Category'" ng-init="filter[prop]={}">

But it does not filter out the property "Category". However if I put a similar filter to exclude "Wine" on the following ng-repeat element, it works fine:

<span class="quarter" ng-repeat="opt in getOptionsFor(prop) | filter:'!Wine'">

I don't understand why I can't filter out property values here. I am very new to angularjs and I'm going out of my mind trying to figure this out. I want to exclude specific property names from the object. either "name" or "category"

I linked the fiddle below. Any help much appreciated! Thanks!

jsfiddle <- link to the fiddle

<div ng-controller="myCtrl">
<div ng-repeat="(prop, ignoredValue) in wines[0]" ng-init="filter[prop]={}">
    <b>{{prop | capitalizeFirst}}:</b><br />
    <span class="quarter" ng-repeat="opt in getOptionsFor(prop)">
        <b><input type="checkbox" ng-model="filter[prop][opt]" />&nbsp;{{opt}}</b>
    </span>
    <hr />
</div>
<div ng-repeat="w in filtered=(wines | filter:filterByProperties)">
    {{w.name}} ({{w.category}})
</div>
<hr />
Number of results: {{filtered.length}}

var app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope) {
$scope.wines = [
    { name: "Wine A", category: "red" },
    { name: "Wine B", category: "red" },
    { name: "wine C", category: "white" },
    { name: "Wine D", category: "red" },
    { name: "Wine E", category: "red" },
    { name: "wine F", category: "white" },
    { name: "wine G", category: "champagne"},
    { name: "wine H", category: "champagne" }    
];
$scope.filter = {};

$scope.getOptionsFor = function (propName) {
    return ($scope.wines || []).map(function (w) {
        return w[propName];
    }).filter(function (w, idx, arr) {
        return arr.indexOf(w) === idx;
    });
};

$scope.filterByProperties = function (wine) {
    // Use this snippet for matching with AND
    var matchesAND = true;
    for (var prop in $scope.filter) {
        if (noSubFilter($scope.filter[prop])) continue;
        if (!$scope.filter[prop][wine[prop]]) {
            matchesAND = false;
            break;
        }
    }
    return matchesAND;
/**/
/*
    // Use this snippet for matching with OR
    var matchesOR = true;
    for (var prop in $scope.filter) {
        if (noSubFilter($scope.filter[prop])) continue;
        if (!$scope.filter[prop][wine[prop]]) {
            matchesOR = false;
        } else {
            matchesOR = true;
            break;
        }
    }
    return matchesOR;
/**/
};

function noSubFilter(subFilterObj) {
    for (var key in subFilterObj) {
        if (subFilterObj[key]) return false;
    }
    return true;
}
});

app.filter('capitalizeFirst', function () {
return function (str) {
    str = str || '';
    return str.substring(0, 1).toUpperCase() + str.substring(1).toLowerCase();
};
});
4
  • The filter does not support filtering on object keys. Commented Aug 15, 2014 at 6:22
  • I see... do you think there is any way that I could easily work around this? @runTarm Commented Aug 15, 2014 at 6:24
  • What is the expected result? In your fiddle, I couldn't figure out anything wrong. Commented Aug 15, 2014 at 6:31
  • I would like to exclude every category: "value" from the object, or every name: "value" Either way really. Basically I want to do this so that say for example, the object included username, id, firstname, lastname etc. I would want to exclude certain keys like id @runTarm Commented Aug 15, 2014 at 6:37

1 Answer 1

1

You could write a simple filter to extract keys first:

app.filter('keys', function () {
    return function (object) {
        return Object.keys(object || {}).filter(function (key) {
            return key !== '$$hashKey'; // this is from ng-repeat
        });
    };
});

and use it like this:

<div ng-repeat="prop in wines[0] | keys | filter:'!Category'"

Example JSFiddle: http://jsfiddle.net/1qhba9fs/1/

Hope this helps.

Sign up to request clarification or add additional context in comments.

5 Comments

I do have one more question, separate from this solution (which worked perfectly) If I wanted to assign the array of filtered wines to a variable in angularjs or javascript, how would I do that? I've been messing around with it all day trying different ways, trying to get one of these functions to return the array and then callback that function and assign it to a global variable. Can't figure it out though... But the general idea is I am just tyring to store the filtered array in a variable... Thanks again, any more help much appreciated!!! @runTarm
jsfiddle.net/wYfs4/15 <- jsfiddle - one more question, probably an easy answer: if you put console.log(w); in the function $scope.getOptionsFor, you'll notice each object gets logged 3 different times. It seems like doing a console log in any of the functions in this app will loop 3 times... why is this?
I'm not sure I understand your first question correctly, but I see you have done it already filtered=(wines | filter:filterByProperties, you should have an access to it by $scope.filtered.
For the second question, that is a nature of angularjs, whenever a digest cycle begin, it will re-evaluate all the watched expresssions repeatedly, until no more change is found (stable). It won't be a problem as long as your expressions run fast. If your filter logic run slow or the list started to grow very LARGE, the best practice is to avoid using filter in the ng-repeat expression, prepare the data beforehand in controller and assign filtered items in a different scope variable, then use it in ng-repeat instead.
Ah I see... that's what I thought. The problem is that I used this sample code and applied it to an existing angular app I've been writing with completely different data and variables. It works fine but somewhere in the process I mixed things up, so if I try to access $scope.filtered I get undefined. I think I can figure that part out. And thank you very much for the quick angular tutorial on ng-repeat, very informative I appreciate it. @runTarm

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.