Reputation: 4783
I have a list of orders and a dropwdown list to filter orders depending on their status. Statuses are: not delivered, fully delivered and partially delivered. Filtering works fine with those 3 options, however I would like to implement one extra option that shows both not delivered and partially delivered orders together.
<select class="form-control" id="status" ng-model="orderFilter.status"
ng-init="orderFilter.status = '_'">
<option value="_">all</option>
<option value="_not" class="text-danger">not delivered</option>
<option value="_part" class="text-info">partially delivered</option>
<option value="n-p" class="text-warning">not and partial</option>
<option value="_done" class="text-success">delivered</option>
</select>
So I've added a new "custom" value, and the way it all works is, it is making copy of objects which are either one or the other, and that is bad, redundant and not what I want.
I thought it may be possible something like:
<option value="_not || _part" class="text-warning">not and partial</option>
Filtering part:
<tr ng-repeat="s in vm.sales | filter: orderFilter">
<td>...</td>
</tr>
Upvotes: 0
Views: 64
Reputation: 1859
If your possible statuses aren't going to change you could use !_done
as your option value which would filter out the _done
but leave _not
and _part
.
var app = angular.module("app", []);
app.controller("controller", function($scope) {
$scope.orderFilter = {
status: "_"
};
$scope.sales = [{
status: "_not",
item: "NOT"
},
{
status: "_part",
item: "PART"
},
{
status: "_done",
item: "DONE"
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.1/angular.min.js"></script>
<div ng-app="app" ng-controller="controller">
<select class="form-control" id="status" ng-model="orderFilter.status">
<option value="_">all</option>
<option value="_not" class="text-danger">not delivered</option>
<option value="_part" class="text-info">partially delivered</option>
<option value="!_done" class="text-warning">not and partial</option>
<option value="_done" class="text-success">delivered</option>
</select> {{orderFilter}}
<table>
<tbody>
<tr ng-repeat="s in sales | filter: orderFilter.status">
<td>{{s.item}}</td>
</tr>
</tbody>
</table>
</div>
Otherwise you'd need to write a custom filter. See the snippet below which let's you add multiple values e.g. "_not, _part"
would return both not and partially delivered items.
var app = angular.module("app", []);
app.controller("controller", function($scope) {
$scope.orderFilter = {
status: ""
};
$scope.sales = [{
status: "_not",
item: "NOT"
},
{
status: "_part",
item: "PART"
},
{
status: "_done",
item: "DONE"
}
];
});
app.filter("filterByProp", function() {
return function(items, prop, filterVal) {
// don't filter if no value to filter on
if (!filterVal) {
return items;
}
// split filter val to allow for multiple props e.g. "_not, _part"
var filters = filterVal.replace(" ", "").split(",");
// only return items which match at least one of the values
return items.filter(function(item) {
return filters.indexOf(item[prop]) > -1
});
};
});;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.1/angular.min.js"></script>
<div ng-app="app" ng-controller="controller">
<select class="form-control" id="status" ng-model="orderFilter.status">
<option value="">all</option>
<option value="_not" class="text-danger">not delivered</option>
<option value="_part" class="text-info">partially delivered</option>
<option value="_not, _part" class="text-warning">not and partial</option>
<option value="_done" class="text-success">delivered</option>
</select> {{orderFilter}}
<table>
<tbody>
<tr ng-repeat="s in sales | filterByProp : 'status' : orderFilter.status">
<td>{{s.item}}</td>
</tr>
</tbody>
</table>
</div>
Upvotes: 0
Reputation: 1635
The best solution is to write your own filter, if you don't want to do that for some reason, than you can filter the list programmaticaly and updating the list depending on selected value:
<select class="form-control" ng-change="filterSales()" id="status" ng-model="orderFilter.status"
ng-init="orderFilter.status = '_'">
<option value="_">all</option>
<option value="_not" class="text-danger">not delivered</option>
<option value="_part" class="text-info">partially delivered</option>
<option value="n-p" class="text-warning">not and partial</option>
<option value="_done" class="text-success">delivered</option>
</select>
And than in your controller somewhere:
$scope.filterSales = function(){
if($scope.orderFilter.status === 'n-p'){
var filteredWithNoStatus = $filter('filter')($scope.vm.sales,'_not');
var filteredWithPartStatus = $filter('filter')($scope.vm.sales,'_part');
$scope.filteredList = Object.assign(filteredWithNoStatus,filteredWithPartStatus);
}else{
$scope.filteredList = $filter('filter')($scope.vm.sales,$scope.orderFilter.status);
}
}
In your html you can remove than the filter
<tr ng-repeat="s in filteredList>
<td>...</td>
</tr>
Sorry that I didn't had the time to test the code, but I hope you understand the Idea.
Upvotes: 1