Im trying to write a custom filter to filter by some checkboxes but havent had any luck, Ive found a solutions here but do not but none fit - would there be a alternative way of writing this checkbox functionality - have I structured this this Angular app incorrectly??
I recreated my little angular app in jsfiddle here (http://jsfiddle.net/samstimpson/vorg019v/):
var someApp = angular.module('someApp', []);
someApp.factory('searchFactory', function(){
return { query: "" }
});
someApp.factory('checkboxFactory', function() {
var checkboxFactory = [
{ name: 'item 1', item: 1 },
{ name: 'item 2', item: 2 },
{ name: 'item 3', item: 3 }
];
return checkboxFactory;
});
someApp.factory('listFactory', function() {
var listFactory = [
{ name: 'list item 01', item: 1 },
{ name: 'list item 02', item: 2 },
{ name: 'list item 03', item: 3 },
{ name: 'list item 04', item: 1 },
{ name: 'list item 05', item: 2 },
{ name: 'list item 06', item: 3 },
{ name: 'list item 07', item: 1 },
{ name: 'list item 08', item: 2 },
{ name: 'list item 09', item: 3 },
{ name: 'list item 10', item: 1 }
];
return listFactory;
});
someApp.filter('filterByCategory', function($filter) {
return function(listItems) {
console.log(listItems);
};
});
someApp.controller('checkboxCtrl', ['$scope','checkboxFactory', 'searchFactory', function($scope, checkboxFactory, searchFactory) {
$scope.checkboxes = checkboxFactory;
$scope.search = searchFactory;
}]);
someApp.controller('listCtrl', ['$scope','listFactory','searchFactory', function($scope, listFactory, searchFactory) {
$scope.listItems = listFactory;
//console.log(search);
$scope.search = searchFactory;
}]);
You need to add a couple of things.
First store the fact that a box is selected in your model :
<input type="checkbox" ng-model="checkbox.selected"/>
Then define your filterByCategory to filter :
someApp.filter('filterByCategory', function() {
return function(input, checkboxes) {
console.log(input, checkboxes);
var ret =[];
for (var i in input){
var match = false;
for (var j in checkboxes){
if (checkboxes[j].selected && checkboxes[j].item == input[i].item){
ret.push(input[i]);
}
}
}
if (ret.length > 0){
return ret;
} else {
return input;
}
};
});
Some explanations about this filter :
a filter function can take n arguments, the first one is the array to filter and the following (arg1, arg2, ...) are parameters you used.
array | filterName:arg1:arg2
We want to filter the listItems with the checkboxes, that's why I'm doing that
Then you need to let your ListController be aware of checkboxes :
someApp.controller('listCtrl', ['$scope','checkboxFactory','listFactory','searchFactory', function($scope, checkboxFactory,listFactory, searchFactory) {
$scope.checkboxes = checkboxFactory;
And finally use your filter in the list :
<li ng-repeat="item in listItems | filter: search.query | filterByCategory : checkboxes">
{{ item.name }}
</li>
All these modifications are available on the fiddle : http://jsfiddle.net/vorg019v/2/
Related
I am new to angularjs and still learning things. I have this code below. What I am aiming here is to load the data into the dropdown from the database. For example the data from the database is New Construction I want to load all data from LoadDropdown function and the New Construction is selected as default.
HTML
<select name="ScopeofWork" class="form-control" ng-model="drpScopeWork" ng-options="SoW as SoW.label for SoW in ScopeOfWorkList">
<option value="" selected hidden></option>
</select>
JS
function LoadDropdown() {
$scope.ScopeOfWorkList = [{ value: 'New Construction', label: 'New Construction' },
{ value: 'Erection', label: 'Erection' },
{ value: 'Addition', label: 'Addition' },
{ value: 'Renovation', label: 'Renovation' },
{ value: 'Repair', label: 'Repair' }];
}
fnLoadDropdown();
function fnLoadDropdown() {
var url = '/AccessoryGroundPreparation/LoadScopeofWork';
$http({
method: "post",
url: url,
//data: { "ScopeOfWork": ScopeOfWork, "projectID": projectID }
}).then(function (res) {
var data = res.data;
if (data.data == null)
LoadDropdown();
else {
// $scope.drpScopeWork = $scope.ScopeOfWorkList[0];
$scope.drpScopeWork = data.data;
}
});
}
Use ng-init to assign a value to your model drpScopeWork form 0 index of your array like ng-init="drpScopeWork = ScopeOfWorkList[0].value"
Here is working code snippet:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.ScopeOfWorkList = [{
value: 'New Construction',
label: 'New Construction'
},
{
value: 'Erection',
label: 'Erection'
},
{
value: 'Addition',
label: 'Addition'
},
{
value: 'Renovation',
label: 'Renovation'
},
{
value: 'Repair',
label: 'Repair'
}
];
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.9/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div>
<select name="ScopeofWork" class="form-control" ng-model="drpScopeWork" ng-options="SoW.value as SoW.label for SoW in ScopeOfWorkList" ng-init="drpScopeWork = ScopeOfWorkList[0].value">
</select>
</div>
</div>
I'm trying to print just the unique values of names but i'm unable to do that.
html code:
<div ng-controller="MyCtrl">
<div><input type="text" ng-model="nameFilter" placeholder="Search..." /></div>
<p ng-repeat="contact in contacts | orderBy: 'customer.name'| unique:'customer.name'">{{ contact.customer.name }}</p>
</div>
JS code:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.nameFilter = '';
$scope.contacts = [
{ id:1, customer: { name: 'foo', id: 10 } },
{ id:2, customer: { name: 'bar', id: 20 } },
{ id:3, customer: { name: 'foo', id: 10 } },
{ id:4, customer: { name: 'bar', id: 20 } },
{ id:5, customer: { name: 'baz', id: 30 } },
{ id:5, customer: { name: 'tar', id: 30 } },
{ id:5, customer: { name: 'got', id: 30 } },
{ id:5, customer: { name: 'man', id: 30 } },
{ id:5, customer: { name: 'baz', id: 30 } },
];
}
the jsfiddle is here: http://jsfiddle.net/nvarun123/0tgL7u6e/73/
This code is working if i remove unique from the ng-repeat.
Here you go, I used the unique filter in angular UI directives, link in the bottom. I have made a small change in the directive for implementing deep finding using string. The details are inside the references.
Here is a demo of the filter.
JSFiddle Demo
Change made inside unique filter.
var extractValueToCompare = function (item) {
if (angular.isObject(item) && angular.isString(filterOn)) {
return deepFind(item,filterOn);
} else {
return item;
}
};
As seen above I am implementing the deepFind function. The function is also provided below.
function deepFind(obj, path) {
var paths = path.split('.')
, current = obj
, i;
for (i = 0; i < paths.length; ++i) {
if (current[paths[i]] == undefined) {
return undefined;
} else {
current = current[paths[i]];
}
}
return current;
}
References:
Angular-UI unique filter
Javascript get deep value by passing path
Here's a simple custom filter that should meet your needs:
app.filter("unique", function thisFilter() {
return function(input){
var seen = { objectNames: [] };
return input.filter(function(obj){
return !seen.objectNames.includes(obj.customer.name)
&& seen.objectNames.push(obj.customer.name)
})
}
});
In this fiddle : http://jsfiddle.net/CBgcP/742/
I'm attempting to pass the result of a custom filter into a scoped function via an onclick :
<span ng-click="open(friend.name | custom)")
This syntax is incorrect. Can the result of a filter operation be passed into a function via on-click ?
fiddle src :
<div ng:app="myApp">
<div ng-controller="HelloCntl">
<ul>
<li ng-repeat="friend in friends | weDontLike:'Adam'">
<span ng-click="open(friend.name | custom)")>{{friend.name}}</span>
<span>{{friend.phone}}</span>
</li>
</ul>
</div>
</div>
span
{
width: 200px;
}
angular.module('myApp',[]).filter('weDontLike', function(){
return function(items, name){
var arrayToReturn = [];
for (var i=0; i<items.length; i++){
if (items[i].name != name) {
arrayToReturn.push(items[i]);
}
}
return arrayToReturn;
};
});
angular.module('myApp', []).filter('custom', function() {
return function(input) {
return input.substring(0 , 2)
};
});
function HelloCntl($scope) {
$scope.open = function(){
console.log('in open');
}
$scope.friends = [
{
name: 'John',
phone: '555-1276'},
{
name: 'Mary',
phone: '800-BIG-MARY'},
{
name: 'Mike',
phone: '555-4321'},
{
name: 'Adam',
phone: '555-5678'},
{
name: 'Julie',
phone: '555-8765'}
];
}
You could use the $filter service to do this:
function HelloCntl($scope, $filter) {
$scope.open = function(friend){
console.log('in open with friend\'s name: ' + friend);
console.log('friend\'s name with filter applied: ' + $filter('custom')(friend);
}
// ...
}
I have a list of companies that have revenue and cost data. In my app, either revenue or cost can be displayed, and the list can be filtered down by a query.
In my controller I have the following two watches:
$scope.$watch('query', function(q) {
$scope.filteredCompanies = $scope.companies
.filter(function(c) { return q ? c.name.toLowerCase().indexOf(q.toLowerCase()) > -1 : true; });
$scope.chartData = {
name: 'companies',
children: $scope.filteredCompanies.map(function(c) {
return {name: c.name, size: c[$scope.selectedItem]};
})
};
});
$scope.$watch('selectedItem', function(i) {
$scope.chartData = {
name: 'companies',
children: $scope.filteredCompanies.map(function(c) {
return {name: c.name, size: c[i]};
})
};
});
My question is, can I tell chartData to watch selectedItem and filteredCompanies, instead of query? I tried the following:
$scope.$watch('[filteredCompanies, selectedItem]', function(arr) {
$scope.chartData = {
name: 'companies',
children: arr[0].map(function(c) {
return {name: c.name, size: c[arr[1]]};
})
};
});
but got the 10 digests iterations reached error.
Not sure what version of angular you are using.. but the 1.2 version of that is..
$scope.$watchCollection('[filteredCompanies, selectedItem]',
function(newValues, oldValues){
$scope.chartData = {
name: 'companies',
children: arr[0].map(function(c) {
return {name: c.name, size: c[arr[1]]};
})
};
});
I also think a third parameter of true will work:
$scope.$watch('[filteredCompanies, selectedItem]',
function () {
},
true
);
Setting up a fiddle now.
In Angular, is there a way to modify the filter such that it only returns exact matches?
Example:
var words = [
{ title: "ball" },
{ title: "wall" },
{ title: "all" },
{ title: "alloy" }
];
var wordsFiltered = filter('filter')
(
words,
{
'title': 'all'
}
);
The above will match 'ball', 'wall', 'all' and 'alloy'. But I would like it to only match 'all'. Any way to change it?
UPDATE
Starting from AngularJS v.1.1.3 the exact filtering is provided natively:
Find words that exactly match title:
<input ng-model="match.title" />
<br>
and exactly match type:
<input ng-model="match.type" />
<hr>
<table>
<tr ng-repeat="word in words | filter:match:true">
<td>{{word.title}}</td>
</tr>
</table>
Plunker
Your question implies that you would want to match against multiple object properties so here's a filter that does that:
app.controller('AppController',
[
'$scope',
function($scope) {
$scope.match = {};
$scope.words = [
{ title: "ball", type: 'object' },
{ title: "wall", type: 'object' },
{ title: "all", type: 'word' },
{ title: "alloy", type: 'material' }
];
}
]
);
app.filter('exact', function(){
return function(items, match){
var matching = [], matches, falsely = true;
// Return the items unchanged if all filtering attributes are falsy
angular.forEach(match, function(value, key){
falsely = falsely && !value;
});
if(falsely){
return items;
}
angular.forEach(items, function(item){ // e.g. { title: "ball" }
matches = true;
angular.forEach(match, function(value, key){ // e.g. 'all', 'title'
if(!!value){ // do not compare if value is empty
matches = matches && (item[key] === value);
}
});
if(matches){
matching.push(item);
}
});
return matching;
}
});
<body ng-controller="AppController">
Find words that exactly match title:
<input ng-model="match.title" />
<br>
and exactly match type:
<input ng-model="match.type" />
<hr>
<table>
<tr ng-repeat="word in words | exact:match">
<td>{{word.title}}</td>
</tr>
</table>
</body>
PLUNKER
Try this :
var words = [
{ title: "ball" },
{ title: "wall" },
{ title: "all" },
{ title: "alloy" }
];
var wordsFiltered = filter('filter')
(
words,
{
'title': 'all'
},
true
);
You can use Regex to achieve a simple implementation:
<input ng-model="query" />
<tr ng-repeat="word in words | filter: myFilter">
In the controller:
$scope.myFilter = function (word) {
if ($scope.query === '') return true;
var reg = RegExp("^" + $scope.query + "$");
return reg.test(word.title);
};
I would create a new filter. Is this what you want?
HTML
<div ng-controller="MyCtrl">
{{words | exactMatch:'all'}} !
</div>
JavaScript
var myApp = angular.module('myApp',[]);
myApp.filter('exactMatch', function() {
return function(words, pattern) {
var result = [];
words.forEach(function (word) {
if (word.title === pattern) {
result.push(word);
}
});
return result;
}
});
function MyCtrl($scope) {
$scope.words = [
{title: "ball", other: 1},
{title: "wall", other: 2},
{title: "all", other: 3},
{title: "alloy", other: 4},
{title: "all", other: 5},
];
}
JsFiddle: jsfiddle
More information about custom filters: filters, creating custom filters and using filters
If you want use filter in Javascript instead of html you should look here: jsfiddle
I created my own filter.
<select
ng-model="selection.neType"
ng-options="option.NE_TYPE_ID as option.NAME for option in networkElementTypes">
<option value="">Todos</option>
</select>
<select
ng-model="selection.neTypeVendor"
ng-options="option.VENDOR_TYPE_ID as option.NAME for option in networkElementTypeVendors | exactMatch: {FK_NE_TYPE_ID: selection.neType}">
<option value="">All</option>
</select>
app.filter('exactMatch', function() {
return function(elements, pattern) {
var result = [];
var fieldSearch = Object.keys(pattern)[0];
elements.forEach(function (element) {
if (element[fieldSearch] == pattern[fieldSearch]) {
result.push(element);
}
});
return result;
}
});
angular-filter is a useful library of filters.
One of their filters is the where filter that does an exact match.