I need to display the field seconddate if it is greater than firstdate, otherwise second field should not be displayed. The date format is in dd mmm yyyy (for eg, 22 Nov 2017). The function is returning true or false. But don't know how to pass this in ng-repeat. if i put this function in ng-if, it is return nothing. Any help would be appreciate. Below is the code:
Json:
GetDetails:
{
Displaydetails:
{
employees: [
{
"name" : "Anu",
"city" : "abc",
"firstdate" : "12 Dec 2004",
"seconddate" : "31 Nov 2014"
},
{
"name" : "Anu",
"city" : "abc",
"firstdate" : "12 Dec 2004",
"seconddate" : "31 Nov 2014"
},
{
"name" : "Anu",
"city" : "abc",
"firstdate" : "12 Dec 2004",
"seconddate" : "31 Nov 2014"
},
{
"name" : "Anu",
"city" : "abc",
"firstdate" : "12 Dec 2004",
"seconddate" : "31 Nov 2014"
}
]
}
}
HTML:
<div ngcontroller = "mycontroller as myctrl" ng-repeat="employee in myctrl.empdetails.employees">
<div>
name
</div>
<div>
{{employee.name}}
</div>
<div>
city
</div>
<div>
{{employee.city}}
</div>
<div>
firstdate
</div>
<div>
{{employee.firstdate}}
</div>
<div ng-if="employee.showdate()>
<div>
seconddate
</div>
<div ng-if="employee.keepgoing == true">
{{employee.seconddate}}
</div>
</div>
Controller:
function myController ($scope,$rootScope,myService)
{
var ctrl = this;
ctrl.initfunc = function()
{
myService.getempDetails().then(function()
{
ctrl.empdetails=myservice.empack;
}
ctrl.showdate =function()
{
var keepgoing = true;
ctrl.dateval = ctrl.empdetails.employees;
angular.forEach (dateval, function(value, key)
{
var firstdateval = new Date (value.firstdate);
var seconddaateval = new Date (value.seconddate);
if(Date.parse(firstdateval) < Date.parse(seconddateval))
{
keepgoing = true;
}
else
{
keepgoing = false;
}
});
}
}
}
function myservice()
{
this.getempDetails = function(req)
{
var request = {
url:jsonfilepath,
method: 'GET'
}
return this.makecall(request) . then(function(response)
{
var res = response.data;
if(res)
{
this.empack = res.displaydetails.employees;
}
}
}
}
As per my understanding you want to show second date if it is greater than firstdate
html :
<div ng-if="myctrl.showdate(employee)">
<div>
seconddate
</div>
<div ng-bind="employee.seconddate"></div>
</div>
myctrl.showdate(employee) will check seconddate display or not for each emploee
js
ctrl.initfunc = function()
{
myService.getempDetails().then(function()
{
ctrl.empdetails=myservice.empack;
}
}
ctrl.showdate = function(employee) {
if (Date.parse(employee.firstdateval) <
Date.parse(employee.seconddateval)) {
return true;
}
return false;
}
You can define ctrl.showdate function outside of ctrl.initfunc function
I want to use the filter in angular and want to filter for multiple values, if it has either one of the values then it should be displayed.
I have for example this structure:
An object movie which has the property genres and I want to filter for Action and Comedy.
I know I can do filter:({genres: 'Action'} || {genres: 'Comedy'}), but what to do if I want to filter it dynamically. E.g. filter: variableX
How do I set variableX in the $scope, when I have an array of the genres I have to filter?
I could construct it as a string and then do an eval() but I don't want to use eval()...
I would just create a custom filter. They are not that hard.
angular.module('myFilters', []).
filter('bygenre', function() {
return function(movies,genres) {
var out = [];
// Filter logic here, adding matches to the out var.
return out;
}
});
template:
<h1>Movies</h1>
<div ng-init="movies = [
{title:'Man on the Moon', genre:'action'},
{title:'Meet the Robinsons', genre:'family'},
{title:'Sphere', genre:'action'}
];" />
<input type="checkbox" ng-model="genrefilters.action" />Action
<br />
<input type="checkbox" ng-model="genrefilters.family" />Family
<br />{{genrefilters.action}}::{{genrefilters.family}}
<ul>
<li ng-repeat="movie in movies | bygenre:genrefilters">{{movie.title}}: {{movie.genre}}</li>
</ul>
Edit here is the link: Creating Angular Filters
UPDATE: Here is a fiddle that has an exact demo of my suggestion.
You can use a controller function to filter.
function MoviesCtrl($scope) {
$scope.movies = [{name:'Shrek', genre:'Comedy'},
{name:'Die Hard', genre:'Action'},
{name:'The Godfather', genre:'Drama'}];
$scope.selectedGenres = ['Action','Drama'];
$scope.filterByGenres = function(movie) {
return ($scope.selectedGenres.indexOf(movie.genre) !== -1);
};
}
HTML:
<div ng-controller="MoviesCtrl">
<ul>
<li ng-repeat="movie in movies | filter:filterByGenres">
{{ movie.name }} {{ movie.genre }}
</li>
</ul>
</div>
Creating a custom filter might be overkill here, you can just pass in a custom comparator, if you have the multiples values like:
$scope.selectedGenres = "Action, Drama";
$scope.containsComparator = function(expected, actual){
return actual.indexOf(expected) > -1;
};
then in the filter:
filter:{name:selectedGenres}:containsComparator
Here is the implementation of custom filter, which will filter the data using array of values.It will support multiple key object with both array and single value of keys. As mentioned inangularJS API AngularJS filter Doc supports multiple key filter with single value, but below custom filter will support same feature as angularJS and also supports array of values and combination of both array and single value of keys.Please find the code snippet below,
myApp.filter('filterMultiple',['$filter',function ($filter) {
return function (items, keyObj) {
var filterObj = {
data:items,
filteredData:[],
applyFilter : function(obj,key){
var fData = [];
if (this.filteredData.length == 0)
this.filteredData = this.data;
if (obj){
var fObj = {};
if (!angular.isArray(obj)){
fObj[key] = obj;
fData = fData.concat($filter('filter')(this.filteredData,fObj));
} else if (angular.isArray(obj)){
if (obj.length > 0){
for (var i=0;i<obj.length;i++){
if (angular.isDefined(obj[i])){
fObj[key] = obj[i];
fData = fData.concat($filter('filter')(this.filteredData,fObj));
}
}
}
}
if (fData.length > 0){
this.filteredData = fData;
}
}
}
};
if (keyObj){
angular.forEach(keyObj,function(obj,key){
filterObj.applyFilter(obj,key);
});
}
return filterObj.filteredData;
}
}]);
Usage:
arrayOfObjectswithKeys | filterMultiple:{key1:['value1','value2','value3',...etc],key2:'value4',key3:[value5,value6,...etc]}
Here is a fiddle example with implementation of above "filterMutiple" custom filter.
:::Fiddle Example:::
If you want to filter on Array of Objects then you can give
filter:({genres: 'Action', key :value }.
Individual property will be filtered by particular filter given for that property.
But if you wanted to something like filter by individual Property and filter globally for all properties then you can do something like this.
<tr ng-repeat="supp in $data | filter : filterObject | filter : search">
Where "filterObject" is an object for searching an individual property and "Search" will search in every property globally.
~Atul
I've spent some time on it and thanks to #chrismarx, I saw that angular's default filterFilter allows you to pass your own comparator. Here's the edited comparator for multiple values:
function hasCustomToString(obj) {
return angular.isFunction(obj.toString) && obj.toString !== Object.prototype.toString;
}
var comparator = function (actual, expected) {
if (angular.isUndefined(actual)) {
// No substring matching against `undefined`
return false;
}
if ((actual === null) || (expected === null)) {
// No substring matching against `null`; only match against `null`
return actual === expected;
}
// I edited this to check if not array
if ((angular.isObject(expected) && !angular.isArray(expected)) || (angular.isObject(actual) && !hasCustomToString(actual))) {
// Should not compare primitives against objects, unless they have custom `toString` method
return false;
}
// This is where magic happens
actual = angular.lowercase('' + actual);
if (angular.isArray(expected)) {
var match = false;
expected.forEach(function (e) {
e = angular.lowercase('' + e);
if (actual.indexOf(e) !== -1) {
match = true;
}
});
return match;
} else {
expected = angular.lowercase('' + expected);
return actual.indexOf(expected) !== -1;
}
};
And if we want to make a custom filter for DRY:
angular.module('myApp')
.filter('filterWithOr', function ($filter) {
var comparator = function (actual, expected) {
if (angular.isUndefined(actual)) {
// No substring matching against `undefined`
return false;
}
if ((actual === null) || (expected === null)) {
// No substring matching against `null`; only match against `null`
return actual === expected;
}
if ((angular.isObject(expected) && !angular.isArray(expected)) || (angular.isObject(actual) && !hasCustomToString(actual))) {
// Should not compare primitives against objects, unless they have custom `toString` method
return false;
}
console.log('ACTUAL EXPECTED')
console.log(actual)
console.log(expected)
actual = angular.lowercase('' + actual);
if (angular.isArray(expected)) {
var match = false;
expected.forEach(function (e) {
console.log('forEach')
console.log(e)
e = angular.lowercase('' + e);
if (actual.indexOf(e) !== -1) {
match = true;
}
});
return match;
} else {
expected = angular.lowercase('' + expected);
return actual.indexOf(expected) !== -1;
}
};
return function (array, expression) {
return $filter('filter')(array, expression, comparator);
};
});
And then we can use it anywhere we want:
$scope.list=[
{name:'Jack Bauer'},
{name:'Chuck Norris'},
{name:'Superman'},
{name:'Batman'},
{name:'Spiderman'},
{name:'Hulk'}
];
<ul>
<li ng-repeat="item in list | filterWithOr:{name:['Jack','Chuck']}">
{{item.name}}
</li>
</ul>
Finally here's a plunkr.
Note: Expected array should only contain simple objects like String, Number etc.
you can use searchField filter of angular.filter
JS:
$scope.users = [
{ first_name: 'Sharon', last_name: 'Melendez' },
{ first_name: 'Edmundo', last_name: 'Hepler' },
{ first_name: 'Marsha', last_name: 'Letourneau' }
];
HTML:
<input ng-model="search" placeholder="search by full name"/>
<th ng-repeat="user in users | searchField: 'first_name': 'last_name' | filter: search">
{{ user.first_name }} {{ user.last_name }}
</th>
<!-- so now you can search by full name -->
You can also use ngIf if the situation permits:
<div ng-repeat="p in [
{ name: 'Justin' },
{ name: 'Jimi' },
{ name: 'Bob' }
]" ng-if="['Jimi', 'Bob'].indexOf(e.name) > -1">
{{ p.name }} is cool
</div>
The quickest solution that I've found is to use the filterBy filter from angular-filter, for example:
<input type="text" placeholder="Search by name or genre" ng-model="ctrl.search"/>
<ul>
<li ng-repeat="movie in ctrl.movies | filterBy: ['name', 'genre']: ctrl.search">
{{movie.name}} ({{movie.genre}}) - {{movie.rating}}
</li>
</ul>
The upside is that angular-filter is a fairly popular library (~2.6k stars on GitHub) which is still actively developed and maintained, so it should be fine to add it to your project as a dependency.
I believe this is what you're looking for:
<div>{{ (collection | fitler1:args) + (collection | filter2:args) }}</div>
Please try this
var m = angular.module('yourModuleName');
m.filter('advancefilter', ['$filter', function($filter){
return function(data, text){
var textArr = text.split(' ');
angular.forEach(textArr, function(test){
if(test){
data = $filter('filter')(data, test);
}
});
return data;
}
}]);
Lets assume you have two array, one for movie and one for genre
Just use the filter as: filter:{genres: genres.type}
Here genres being the array and type has value for genre
I wrote this for strings AND functionality (I know it's not the question but I searched for it and got here), maybe it can be expanded.
String.prototype.contains = function(str) {
return this.indexOf(str) != -1;
};
String.prototype.containsAll = function(strArray) {
for (var i = 0; i < strArray.length; i++) {
if (!this.contains(strArray[i])) {
return false;
}
}
return true;
}
app.filter('filterMultiple', function() {
return function(items, filterDict) {
return items.filter(function(item) {
for (filterKey in filterDict) {
if (filterDict[filterKey] instanceof Array) {
if (!item[filterKey].containsAll(filterDict[filterKey])) {
return false;
}
} else {
if (!item[filterKey].contains(filterDict[filterKey])) {
return false;
}
}
}
return true;
});
};
});
Usage:
<li ng-repeat="x in array | filterMultiple:{key1: value1, key2:[value21, value22]}">{{x.name}}</li>
Angular Or Filter Module
$filter('orFilter')([{..}, {..} ...], {arg1, arg2, ...}, false)
here is the link: https://github.com/webyonet/angular-or-filter
I had similar situation. Writing custom filter worked for me. Hope this helps!
JS:
App.filter('searchMovies', function() {
return function (items, letter) {
var resulsts = [];
var itemMatch = new RegExp(letter, 'i');
for (var i = 0; i < items.length; i++) {
var item = items[i];
if ( itemMatch.test(item.name) || itemMatch.test(item.genre)) {
results.push(item);
}
}
return results;
};
});
HTML:
<div ng-controller="MoviesCtrl">
<ul>
<li ng-repeat="movie in movies | searchMovies:filterByGenres">
{{ movie.name }} {{ movie.genre }}
</li>
</ul>
</div>
Here is my example how create filter and directive for table jsfiddle
directive get list (datas) and create table with filters
<div ng-app="autoDrops" ng-controller="HomeController">
<div class="row">
<div class="col-md-12">
<h1>{{title}}</h1>
<ng-Multiselect array-List="datas"></ng-Multiselect>
</div>
</div>
</div>
my pleasure if i help you
Too late to join the party but may be it can help someone:
We can do it in two step, first filter by first property and then concatenate by second filter:
$scope.filterd = $filter('filter')($scope.empList, { dept: "account" });
$scope.filterd = $scope.filterd.concat($filter('filter')($scope.empList, { dept: "sales" }));
See the working fiddle with multiple property filter
OPTION 1:
Using Angular providered filter comparator parameter
// declaring a comparator method
$scope.filterBy = function(actual, expected) {
return _.contains(expected, actual); // uses underscore library contains method
};
var employees = [{name: 'a'}, {name: 'b'}, {name: 'c'}, {name: 'd'}];
// filter employees with name matching with either 'a' or 'c'
var filteredEmployees = $filter('filter')(employees, {name: ['a','c']}, $scope.filterBy);
OPTION 2:
Using Angular providered filter negation
var employees = [{name: 'a'}, {name: 'b'}, {name: 'c'}, {name: 'd'}];
// filter employees with name matching with either 'a' or 'c'
var filteredEmployees = $filter('filter')($filter('filter')(employees, {name: '!d'}), {name: '!b'});
My solution
ng-repeat="movie in movies | filter: {'Action'} + filter: {'Comedy}"
the best answer is :
filter:({genres: 'Action', genres: 'Comedy'}
The result of list returned by the filter test_id needs to be checked.If the list is null need to call a function in the controller.
<div class="test_list">
<ul>
<p> testID :{{test_id}}</p>-->
<li ng-repeat="test in test_list | filter: test_id">
{{test}}
</li>
</ul>
</div>
Thanks in advance.
Add a watch over the list variable in your controller and filter it programatically and call the necessary function if found null.
$scope.$watch("test_id", function(new_test_id) {
//inject $filter service in your main controller
var filtered_test_val=$filter('filter')($scope.test_val, new_test_id, false);
if(angular.isUndefined(filtered_test_val) || filtered_test_val== null)
{
//call your function here.
}
}
You just need a custome filterfor this :-)
<div ng-app="myapp">
<div ng-controller="test">
<input type="text" ng-model="search">
<div ng-repeat="data in myData | filterData:search">
{{ data.ID }}
{{ data.Message }}
</div>
</div>
</div>
angular.module('myapp',[])
.controller('test',function($scope){
$scope.myData = [
{
"ID" : "001",
"Message" : "test test test test"
},
{
"ID" : "002",
"Message" : "test test test test"
},
{
"ID" : "003",
"Message" : "test test test test"
},
{
"ID" : "004",
"Message" : "test test test test"
},
{
"ID" : "005",
"Message" : " "
},
{
"ID" : "006",
"Message" : "test test test test"
},
{
"ID" : "007",
"Message" : "test test test test"
},
{
"ID" : "007",
"Message" : null
}
];
})
.filter('filterData',function(){
return function(data,search) {
if(!search || search.length<3){
return data;
}
var dataToBePushed = [];
for(var i=0;i<data.length;i++){
if(data[i].ID==search){
dataToBePushed.push(data[i]);
}
}
if(dataToBePushed.length==0){
alert("My function");
}else{
return dataToBePushed;
}
}
});
PS:- I checked the search after length is 3 but it may help you to clear the idea and you can manupilate it according to your requirement.
Fiddle
You can make use of the built-in filter filter in your own custom defined filter.
.filter('checknull', function($filter) {
return function(x, test) {
var result = $filter("filter")(x, test);
if (result.length <= 0)
myFunc();
return result;
}
});
Fiddle Here
I have successfully been able to send data to the firebase server however I am having trouble getting the data to send to the appropriate data subset I have created. When I send data made in the html form, It sends organized by ID number. I need it to be sent as a child to the 'groups' category in firebase.
here is a Plnkr with the server and $add working. Any suggestions I would really appreciate!
http://plnkr.co/edit/LZ24sRoSJjuCHQnEGzQz?p=linter
.controller('MainCtrl', ['$scope', 'groupsService', function( $scope, groupsService, $firebase ) {
$scope.newGroup = {
name: '',
status: ''
};
$scope.addGroup = function(newGroup) {
groupsService.addGroup(newGroup);
$scope.newGroup = {
name: '',
status: ''
};
};
$scope.updateGroup = function (id) {
groupsService.updateGroup(id);
};
$scope.removeGroup = function(id) {
groupsService.removeGroup(id);
};
}])
.factory('groupsService', ['$firebase', 'FIREBASE_URI',
function ($firebase, FIREBASE_URI) {
var ref = new Firebase(FIREBASE_URI);
var groups = $firebase(ref).$asArray();
var getGroups = function(){
return groups;
};
var addGroup = function (newGroup) {
console.log(newGroup)
groups.$add(newGroup);
};
var updateGroup = function (id){
groups.$save(id);
};
var removeGroup = function (id) {
groups.$remove(id);
};
return {
getGroups: getGroups,
addGroup: addGroup,
updateGroup: updateGroup,
removeGroup: removeGroup,
}
}]);
Thanks for responding! What I am trying to do is add dummy data (name and status) to the groups category like this:
{
Groups:[
"-JcFXid1A2G8EM7A_kwc" : {
"name" : "hi",
"status": "inactive"
},
"-JcFZP5FNtL4Yj6nja_7" : {
"name" : "hi"
"status": "inactive"
},
"-JcFtGoZL7J-CCIjTYcL" : {
"name" : "dfgdfg",
"status": "inactive"
}
]
}
would it make more sense to have them organized by active or inactive? I am afraid to nest too far in firebase...
like
{
Groups:[
"Active":[
"-JcFXid1A2G8EM7A_kwc" : {
"name" : "hi",
}
],
"Inactive":[
"-JcFZP5FNtL4Yj6nja_7" : {
"name" : "hi"
},
"-JcFtGoZL7J-CCIjTYcL" : {
"name" : "dfgdfg"
}
]
]
}
This isn't an answer to your question yet, because I first need to understand what you're trying to accomplish (and I can't fit this amount of information in a comment).
In your view you have a form that binds to the group's name and status:
<form role="form" ng-controller="MainCtrl" ng-submit="addGroup(newGroup)">
<div class="form-group">
<label for="groupName">Group Name</label>
<input type="text" class="form-control" id="groupName" ng-model="newGroup.name">
</div>
<div class="form-group">
<label for="groupStatus">Group Status</label>
<select class="form-control" ng-model="newGroup.status">
<option value="inactive">Inactive</option>
<option value="active">Active</option>
</select>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
In your GroupsService you essentially add a group like this:
var ref = new Firebase(FIREBASE_URI);
var groups = $firebase(ref).$asArray();
groups.$add(newGroup);
Which adds the group to the collection at that URL.
Which leads to this data structure:
{
"-JcFXid1A2G8EM7A_kwc" : {
"name" : "hi",
"status" : "inactive"
},
"-JcFZP5FNtL4Yj6nja_7" : {
"name" : "hi",
"status" : "active"
},
"-JcFtGoZL7J-CCIjTYcL" : {
"name" : "dfgdfg",
"status" : "active"
}
}
But if I understand you correctly you to want the data to be stored like this:
{
"inactive": [
"-JcFXid1A2G8EM7A_kwc" : {
"name" : "hi"
}
],
"active": [
"-JcFZP5FNtL4Yj6nja_7" : {
"name" : "hi"
},
"-JcFtGoZL7J-CCIjTYcL" : {
"name" : "dfgdfg",
}
]
}
Is this indeed what you're looking to do?
Are you ever going to display active and inactive groups combined in a list? This is important to know, since it is quite easy to filter a list in Angular, but I wouldn't know how to merge two lists.
I have this JSON object.
var UsersList=[
{
"User" : {
"IdUser" : "admin",
"FirstName" : "mirco",
"LastName" : "sabatino"
}
}, {
"User" : {
"IdUser" : "coordinator",
"FirstName" : "coordinator",
"LastName" : ""
}
}, {
"User" : {
"IdUser" : "test",
"FirstName" : "publisher",
"LastName" : "Diaz"
}
}, {
"User" : {
"IdUser" : "work",
"FirstName" : "ingester",
"LastName" : "Brown"
}
}
] ;
I want filter in ng-repeat for LastName value.
<div class="col-md-6" ng-repeat="users in UsersList | filter: {User.LastName : filterSearchLetter}">
filterSearchLetter value in my controler is populated by
$scope.filterLetterUser=function(letter){
$scope.filterSearchLetter=letter;
console.log($scope.filterSearchLetter);
};
But this don't work.
See my plnkr for the solution http://plnkr.co/edit/l27xUQ?p=preview. I also have implemented your required UI behavior using ng-change. Hope it helps.
For detailed explanation I offer you Todd Motto's blog - http://toddmotto.com/everything-about-custom-filters-in-angular-js/
To invoke a filter, the syntax is the filter function name followed by the parameters.
To define a filter you need to do (This is copy of Todd Motto's code modified for your data)
todos.filter('startsWithLetter', function () {
return function (items, letter) {
var filtered = [];
var letterMatch = new RegExp(letter, 'i');
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (letterMatch.test(item.User.LastName.substring(0, 1))) {
filtered.push(item);
}
}
return filtered;
};
});
This is not a valid object: {User.LastName : filterSearchLetter} It should actually throw an exception saying something like
Uncaught SyntaxError: Unexpected token .
What you probably want to try instead is: {"User": {"LastName" : filterSearchLetter} }
To iterate over an array of Objects see:
angularjs - ng-repeat: access key and value from JSON array object
You may have to convert to valid JS object using JS_Obj=JSON.parse(JSON_Obj);
Maybe something like this:
//iterate through array
<ul ng-repeat="users in UsersList">
//iterate through Object
<li ng-repeat=(key, value) in users | filter: {User.LastName : filterSearchLetter}>
{{key}} : {{value}}
</li>
</ul>