AngularJS multiple filter - javascript

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>

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.

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>

Related

Multiple Filters in list.js?

I have two columns that I want to be filterable with list.js. I tried the following code:
var options = {
valueNames: [ 'formformname', 'form-name', 'form-email','form-phone','form-branch','form-message','formstatus','form-assignment' ],
page: 15,
pagination: [{
outerWindow: 2,
}]
};
var userList = new List('users', options);
$('#origin').change(function () {
var selection = this.value;
if (selection) {
userList.filter(function(item) {
return (item.values().formformname == selection);
});
} else {
userList.filter();
}
});
$('#status').change(function () {
var selection = this.value;
if (selection) {
userList.filter(function(item) {
return (item.values().formstatus == selection);
});
} else {
userList.filter();
}
});
And it works fine for each column, the problem is if I select an 'origin' filter, then a 'status' filter, or vice versa, the second selection wipes out the first one. What I want to do is have them function together. Any ideas?
Following creates an array from the selected dropdowns and uses Array#every() to check each item in the list filter.
Note the addition of the data-prop attribute to each <select> in order to determine which column property to filter for each one
var options = {
valueNames: ['name', 'born']
};
var userList = new List('users', options);
const $sels = $('select.table-filter').change((e)=> {
const filterArr = $sels.toArray()
.filter(el => !!el.value)
.map(el =>({prop: el.dataset.prop, value:el.value}))
userList.filter(function(item) {
return !filterArr.length || filterArr.every(f => f.value === item.values()[f.prop]);
});
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Name:
<select class="table-filter" data-prop="name">
<option value="">Choose name</option>
<option value="Jonny Stromberg">Jonny Stromberg</option>
<option value="Jonas Arnklint">Jonas Arnklint</option>
<option value="Martina Elm">Martina Elm</option>
<option value="Gustaf Lindqvist">Gustaf Lindqvist</option>
</select>
Year Born:
<select class="table-filter" data-prop="born">
<option value="">Choose year</option>
<option value="1983">1983</option>
<option value="1985">1985</option>
<option value="1986">1986</option>
</select>
<hr/>
<div id="users">
<table>
<!-- IMPORTANT, class="list" have to be at tbody -->
<tbody class="list">
<tr>
<td class="name">Jonny Stromberg</td>
<td class="born">1986</td>
</tr>
<tr>
<td class="name">Jonas Arnklint</td>
<td class="born">1985</td>
</tr>
<tr>
<td class="name">Martina Elm</td>
<td class="born">1986</td>
</tr>
<tr>
<td class="name">Gustaf Lindqvist</td>
<td class="born">1983</td>
</tr>
</tbody>
</table>
</div>
<script src="//cdnjs.cloudflare.com/ajax/libs/list.js/1.5.0/list.min.js"></script>

Displaying a table based on drop down value

I want to display a table of questions based on what the user selected on the drop down menu. Once the user selects a category, I want to send that data to the api using get method. I'm using angularjs as the controller. The problem is that the table is not being populated by any values after calling the get method. I am not sure if my approach is correct.
html
<h3>View Quiz By:</h3>
<select name="singleSelect" ng-model="data.singleSelect">
<option value="math">Math</option>
<option value="science">Science</option>
<option value="history">History</option>
<option value="compscience">Computer Science</option>
<option value="other">Other</option>
</select>
<tt>singleSelect = {{data.singleSelect}}</tt>
<br><br><br>
<div ng-controller="selectOptionController">
<table>
<tr>
<th>Id</th>
<th>Question</th>
<th>Answer</th>
<th>OptionA</th>
<th>OptionB</th>
<th>OptionC</th>
<th>OptionD</th>
</tr>
<tr ng-repeat="row in result">
<td>{{row.id}}</td>
<td>{{row.question}}</td>
<td>{{row.answer}}</td>
<td>{{row.optionA}}</td>
<td>{{row.optionB}}</td>
<td>{{row.optionC}}</td>
<td>{{row.optionD}}</td>
</tr>
</table>
</div>
angularjs
angular.module('staticSelect', [])
.controller('selectOptionController', ['$scope', function($scope) {
$scope.data = {
singleSelect: null
};
$http.get("http://localhost:8080/quiz/webapi/quiz/"+data)
.then(function(response) {
$scope.result = response.data;
});
}]);
Once the user selects a category, I want to send that data to the api using get method.
You can add ng-change to your <select>
<select name="singleSelect" ng-model="data.singleSelect" ng-change="onChange()">
<option value="math">Math</option>
<option value="science">Science</option>
<option value="history">History</option>
<option value="compscience">Computer Science</option>
<option value="other">Other</option>
</select>
and in Controller write:
$scope.onChange = function(){
$http.get("http://localhost:8080/quiz/webapi/quiz/"+$scope.data.singleSelect)
.then(function(response) {
$scope.result = response.data;
});
};
A a side note:
If you want to build select options by angularjs way use ng-options:
$scope.list = [
{value: 'science', name: 'Science'},
{value: 'history', name: 'History'},
{value: 'compscience', name: 'Computer Science'},
{value: 'other', name: 'Other'}
];
and your select:
<select name="singleSelect"
ng-model="data.singleSelect"
ng-change="onChange(data.singleSelect)"
ng-options="item.value as item.name for item in list"
> </select>
Demo

If Dropdown Selected, push into one array, otherwise, push into a different one

Im programming an app, and i want to push something in a Array, if a Item of the Dropdown is selected, if its not, then it should push it into another Array.
Heres some Code:
html.js
<label class="item item-input item-select">
<div class="input-label">
Muscle
</div>
<select ng-model="selOption">
<option>Chest</option>
<option>Biceps</option>
<option>Back</option>
<option>Stomach</option>
<option>Legs</option>
<option>Triceps</option>
<option>Shoulders</option>
<option>Traps</option>
</select>
</label>
app.js
$scope.selOption = "Chest";
$scope.createEx = function(){
if($selOption = "Chest")
{
$scope.chestEx.push({title:...., reps:....});
console.log("Test");
};
};
I don't know ionic-framework but in angular code and html need to change.
need to use value="someVlue" in your option tag and compare like if($scope.selOption === "Chest") instead of if($selOption = "Chest")
html:
<select ng-model="selOption"> <!--if you want to call on change value then use ng-change="createEx()"-->
<option value="Chest">Chest</option>
<option value="Biceps">Biceps</option>
<option value="Back">Back</option>
<option value="Stomach">Stomach</option>
<option value="Legs">Legs</option>
<option value="Triceps">Triceps</option>
<option value="Shoulders">Shoulders</option>
<option value="Traps">Traps</option>
</select>
and controller code:
$scope.selOption = "Chest";
$scope.createEx = function() {
if($scope.selOption === "Chest"){
$scope.chestEx.push({title:...., reps:....});
console.log("Test");
}
else {// as you need}
};
Another option is to use the ng-change directive and repeat an array of options like this:
https://jsfiddle.net/kdb9ed7f/
Controller
function Controller($scope) {
var vm = this;
vm.myOptions = [];
vm.options = [
'Chest',
'Biceps',
'Back',
'Stomach',
'Legs',
'Triceps',
'Shoulders',
'Traps'
];
vm.checkOption = checkOption;
function checkOption() {
if (vm.options[vm.selOption] == 'Chest') {
vm.myOptions.push({
name: 'Chest'
});
vm.selOption = null;
}
}
}
HTML
<div ng-controller="Controller as ctrl">
<select ng-model="ctrl.selOption" ng-options="k as v for (k,v) in ctrl.options" ng-change="ctrl.checkOption()">
<option>Select One</option>
</select>
<hr>
<ul>
<li ng-repeat="option in ctrl.myOptions">{{option.name}}</li>
</ul>
</div>

Angular filter for gender using select dropdown

I have a database that need to be filtered by gender. Everything is working fine.
But when i filter by gender, as female is part of male, female is also showing up.
If i pick female, then male is hiding off.
Here is my jsfiddle link
<select name="" id="" ng-model="test.filterByGender">
<option value="">By Gender</option>
<option value="female">Female</option>
<option value="male">Male</option>
</select>
This seems to be working.
https://jsfiddle.net/kg2kscnw/14/
<tr ng-repeat="subject in test.subjects | filter:test.filterByState | filter:(!!test.filterByGender || undefined) && test.filterByGender:true | filter:test.filterByAge">
<td>{{subject.name}}</td>
<td>{{subject.gender}}</td>
<td>{{subject.age}}</td>
</tr>
If you set the comparator to true, it sets up a strict comparison of actual and expected, so it can see that 'male' is not the same as 'female'. But then it doesn't recognise the empty value of the 'By gender' field. In order to get around this, you can tell the filter to only be applied if the value is not empty or undefined.
Hope this helps.
From doc
Selects a subset of items from array and returns it as a new array.
It works like String.Contains method. So when you select male from drop-down, it shows all data because female also contains male sub-string.
var app = angular.module("testApp", []);
app.controller('testCtrl', function($scope){
vm = this;
vm.subjects = [
{
name : "Alpha",
location:"TN",
age : "25",
gender:"female"
},
{
name : "Beta",
location:"TN",
age : "44",
gender:"male"
},
{
name : "Gamma",
location:"KE",
age : "20",
gender:"female"
},
{
name : "Theta",
location:"AN",
age : "22",
gender:"female"
},
];
angular.forEach( vm.subjects, function(subject){
if(parseInt(subject.age) <= 25){
subject.ageFilterCriteria = '<25'
}
else{
subject.ageFilterCriteria = '>25'
}
})
console.log(vm.subjects);
vm.filterByAge = '';
vm.filterByState='';
vm.filterByGender='';
vm.setFlag = function(value){
if(value)
vm.flag = true;
else
vm.flag = false;
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="testApp" ng-controller="testCtrl as test">
<select name="" id="" ng-model="test.filterByState">
<option value="">Select a state</option>
<option value="TN">TamilNadu</option>
<option value="KE">Kerala</option>
<option value="AN">Andra Pradesh</option>
</select>
<select name="" id="" ng-model="test.filterByGender" ng-change="test.setFlag(test.filterByGender)">
<option value="">By Gender</option>
<option value="female">Female</option>
<option value="male">Male</option>
</select>
<select name="" id="" ng-model="test.filterByAge">
<option value="">Select All</option>
<option value="<25">Less Than 25</option>
<option value=">25">Greater Than 25</option>
</select>
<table>
<tr ng-repeat="subject in test.subjects |filter:{location:test.filterByState,ageFilterCriteria:test.filterByAge}| filter:{gender:test.filterByGender}:test.flag">
<td>{{subject.name}}</td>
<td>{{subject.gender}}</td>
<td>{{subject.age}}</td>
</tr>
</table>
</div>
try this:
<select name="" id="" ng-model="test.filterByGender" ng-change="test.flag =true">
<option value="">By Gender</option>
<option value="female">Female</option>
<option value="male">Male</option>
</select>
<tr ng-repeat="subject in test.subjects |filter:{location:test.filterByState,ageFilterCriteria:test.filterByAge}|
filter:{gender:test.filterByGender}:test.flag">
Actually Filter give the result on the basis of matching items.So female rows are showing when you select male from drop-down because "female" word contains the "male" word .

Angular ng-repeat ignoring nested ng-if

Howdie do,
I'm attempting to only display an option if the code that the client used to login, matches the $scope.code in the controller.
The HTML should then display the option that matches the code the client logged in with.
View:
<div class="">
<select id="customer-dd" ng-model="selectedCustomer" ng-repeat="(group, msg) in codes">
<option value="">select...</option>
<div ng-if=" 'group' == 'code' ">
<option value="{{ group }} ">{{ msg }}</option>
</div>
</select>
</div>
Controller:
$scope.code = dataFactory.getCode();
$scope.codes = {
'ABC': 'First option',
'DEF': 'Second option'
}
There should only be one option showing as a client can't login with more than one code at a time
However, when I run this, I keep getting two input boxes instead of just the one that matches the code.
Is there something I'm missing here?
* UPDATE *
I've updated the code to the following and multiple options are still being printed:
<div class="">
<select id="customer-dd" ng-model="selectedCustomer" ng-repeat="(group, msg) in codes">
<option value="">select...</option>
<div ng-if=" group == code ">
<option value="{{ group }} ">{{ msg }}</option>
</div>
</select>
</div>
* UPDATE *
#ieaglle Removing the div allowed the if statement to excecute. The updated HTML is now:
<div class="">
<select id="customer-dd" ng-model="selectedCustomer" ng-repeat="(group, msg) in codes">
<option value="">select...</option>
<option ng-if=" group == code " value="{{ group }} ">{{ msg }}</option>
</select>
</div>
THANKKKK UUUU!!!
Try using ng-options instead with a filtered object.
http://jsfiddle.net/joshdmiller/hb7lu/
HTML:
<select ng-model="selectedCustomer" ng-options="msg for (group, msg) in filterObjsByProp(codes)"></select>
JS:
$scope.code = 'ABC';
$scope.codes = {
'ABC': 'First option',
'DEF': 'Second option'
};
$scope.filterObjsByProp = function (items) {
var result = {};
angular.forEach(items, function (value, key) {
if (key === $scope.code) {
result[key] = value;
}
});
return result;
}
Although this is overkill, since an object cannot have multiple properties with the same name, so you will only ever have 1 option in the select. As such, maybe a select is not the best option here, or maybe an array with key/value objects is better.
Change your HTML to this.
Notice the change in the ng-if statement.
<div class="">
<select id="customer-dd" ng-model="selectedCustomer">
<option value="{{ group }}" ng-repeat="(group, msg) in codes">select...
<div ng-if=" group == code ">
{{ msg }}
</div>
</option>
</select>
</div>

Categories