I have a list of products. Each product has three properties: mustBuy, promotion (both booleans) and productName. What I'm trying to do is to apply one filter at the time, based on the user input. If the user clicks on a button called "Must buy", the products will be filtered by the mustBuy field, so once I click that button I should only see the products that have a mustBuy property with a value of true. I want to generate those filter buttons in a dynamic manner because I might add extra properties later on. Right now I have a list of hard coded buttons used for filtering:

        <a ng-click="myFilter = {mustBuy:true}">
            <img src="/images/must-filter.png" />
        </a>
        <a ng-click="myFilter = {promotion:true}">
            <img src="/images/promo-filter.png" />
        </a>

This is what "myFilter" filters.

<div ng-repeat="product in products | filter:myFilter">...</div>

It works fine but I want to make those filters dynamic as I'll add more in the future. This is what I've tried: (v1): Js controller:

        $scope.filters = [{ image: "must-filter.png", myFilter: { mustBuy: true } }, { image: "promo-filter.png", myFilter: { promotion: true } }];

Html:

        <a ng-repeat="f in filters | filter:f.myFilter">
            <img src="/images/{{f.image}}" />
        </a>

(v2): Js controller:

        $scope.filters = [{ image: "must-filter.png", myFilter: { mustBuy:true } }, { image: "promo-filter.png",  myFilter: {promotion:true} }];

Html:

        <a ng-repeat="f in filters"
           ng-click="{{f.myFilter}}">
            <img src="/images/{{f.image}}" />
        </a>

(v3):

Js controller:

       $scope.filters = [{ image: "must-filter.png", myFilter: "myFilter = {mustBuy:true}" }, { image: "promo-filter.png",  myFilter: "myFilter = {promotion:true}" }];

Html:

        <a ng-repeat="f in filters"
           ng-click="{{f.myFilter}}">
            <img src="/images/{{f.image}}" />
        </a>

The third approach (v3) has EXACTLY the same HTML output the original (hardcoded) approach had, except it doesn't work, which makes me think there is something more (binding) happening behind the scenes? How can I achieve the functionality described in the first paragraph?

有帮助吗?

解决方案

Without looking too much (read at all) why your attempts failed, you can achieve what you want like this:

1.)
Define a list of filters and the currently selected (applied) filter in the contoller:

$scope.filters = [
    {name: 'none',      filterExpr: ''},
    {name: 'must buy',  filterExpr: {mustBuy: true}},
    {name: 'promotion', filterExpr: {promotion: true}}
];
$scope.selectedFilter = $scope.filters[0];

(My filter-object have a name and a filterExpr, but you can adjust them to your needs.)


2.)
Define a function for changing the applied filter (again in the contoller of course):

$scope.setFilter = function (filter) {
    $scope.selectedFilter = filter;
};

3.)
Let the user change the applied filter (in the view):

<ul>
    <li ng-repeat="filter in filters">
        <a href="" ng-click="setFilter(filter)">{{filter.name}}</a>
    </li>
</ul>

4.)
Filter the items, based on the currently selected filter's filter-expression:

<ul>
    <li ng-repeat="item in items | filter:selectedFilter.filterExpr">
        {{item.description}}
    </li>
</ul>

See, also, this short demo.

其他提示

As you can see in this FIDDLE, you must use a function or custom filter to chain your dynamic filters.

Filter set:

//this set will filter everything but true-false
$scope.set1 = [function(item){return item.mustBuy;},
               function(item){return !item.promotion}];

Filter function:

$scope.multipleFilters = function(item){
    var v = true;
    for(var i=0; i<$scope.set1.length; i++){
        v = v && $scope.set1[i](item);
    }
    return v;
};

Use like this:

<div ng-repeat="product in products | filter:multipleFilters">
    {{product.mustBuy}} - {{product.promotion}}
</div>

The point is using functions for filters like function(item){return item.mustBuy}, not expressions like {mustBuy:true}

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top