orderBy dd/mm/yyyy by year angular - angularjs

The data I am receiving from a webservice is formatted as dd/mm/yyyy. The problem with this is when sorting, it sorts by dd rather than yyyy.
<td ng-repeat="thead in resultHeader">
{{thead.head}}
<span class="sortorder" ng-show="predicate === thead.line" ng-class="{reverse:reverse}"></span>
</td>
Controller:
$scope.order = function(predicate) {
var results = $scope.model.resultList;
$scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
$scope.predicate = predicate;
$scope.model.currentPage = 1;
$scope.model.beginFrom = 0;
};
How can I sort this data by yyyy with my current set up?
{
"name": "Test",
"ShipmentDate": "06\/08\/2012"
}

The key part is to add a $filter to your module and use that $filter to get the Date value from the string. you can use Date.parse('dd/mm/yyyy') to get the time in float, and then run an Array.sort() to your data.

If you converted your date strings to Date objects, you can use the orderBy: filter to sort by date.
<td ng-repeat="thead in resultHeader | orderBy:'ShipmentDate':shouldBeReversedOrder ">
{{thead.head}}
<span class="sortorder" ng-show="predicate === thead.line" ng-class="{reverse:reverse}"></span>
</td>
When you want to display the date back in a proper formate you can use {{thead.ShipmentDate | 'yyyy-mm-dd'}} to format it for you.

Use the custom order for this. Look:
function MyCtrl($scope, orderByFilter) {
$scope.sortedFriends = [
{
name: 'John',
age: 25,
dateTest: '10/10/2015'
}, {
name: 'Jimmy',
age: 25,
dateTest: '10/12/2015'
},{
name: 'Mary',
age: 28,
dateTest: '10/09/2009'
}, {
name: 'Ed',
age: 27,
dateTest: '30/03/2014'
},{
name: 'Andrew',
age: 27,
dateTest: '11/11/2016'
}];
$scope.orderByCustom = function(friend) {
console.log(friend)
return friend.dateTest.split('/')[2];
};
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="MyCtrl">
<ul>
<li ng-repeat="friend in sortedFriends | orderBy:orderByCustom"">
{{friend}}
</li>
</ul>
</div>

Related

How to handle 'ng-repeat' together 'ng-model' for individual object.?

I have an array with objects with 'SALARY' field. I want to manage 'CREDIT' amount using ng-model. so i am create a function and work fine with object id. but in my case when i am change value of any input field it is change all input's values.
Please any one tell me how to possible change input value only desire input field.
this is my html >
<div ng-repeat="obj in myObj">
{{obj.id}} /
{{obj.name}} /
{{obj.salary}} /
<input type="text" ng-model="credit.amount" />
<button ng-click="updateBalance(obj)">Balance</button>
</div>
and this is my script >
var app = angular.module('myApp',[]);
app.controller('employee', function($scope) {
$scope.myObj = [
{ "id" : 1, "name" : "abc", "salary" : 10000 },
{ "id" : 2, "name" : "xyz", "salary" : 15000 }
]
$scope.credit = {"amount" : 0};
$scope.updateBalance = function(obj){
console.log(obj.name + "'s current balance is : ");
console.log(obj.salary - Number($scope.credit.amount));
}
});
and this is my PLNKR LINK.
Values in all input fields are changing because you are binding $scope.credit.amount to all of them. Instead you need to maintain them separately. Following should work:
Html
<tr ng-repeat="obj in myObj">
<td>{{obj.id}} </td>
<td>{{obj.name}} </td>
<td>{{obj.salary}} </td>
<td>
<input type="number" ng-model="credits[obj.id].amount" />
</td>
<td>
<button ng-click="updateBalance(obj)">Balance</button>
</td>
</tr>
Controller
var app = angular.module('myApp', []);
app.controller('employee', function($scope) {
$scope.myObj = [{
"id": 1,
"name": "abc",
"salary": 10000
}, {
"id": 2,
"name": "xyz",
"salary": 15000
}]
$scope.credits = $scope.myObj.reduce(function(acc, object) {
acc[object.id] = { amount: 0 };
return acc;
}, {});
$scope.updateBalance = function(obj) {
var balance = obj.salary - Number($scope.credits[obj.id].amount)
alert(obj.name + ' balance is : ' + balance);
}
});

How to filter ng-repeat list on empty string values with an inputfield?

How can I filter an ng-repeat to show all items where a certain columnfield is an empty string? When I try this by typing nothing in the field it always seem to give the full list (wich is expected). I only want to see the person with id 1. How can I adjust the filter that a certain character in the inputfield makes the ng repeat filter on empty fields for the name column.
FiddleJs Example
My view:
<div class="panel-heading">
<h3>Filtered by {{filterValue}}</h3>
<input ng-change="filter()" ng-model="filterValue"/>
</div>
<div class="panel-body">
<ul class="list-unstyled">
<li ng-repeat="p in filteredPeople">
<h4>{{p.name}} ({{p.age}}) id: {{p.id}}</h4>
</li>
</ul>
</div>
Controller:
var people = [{
name: '',
age: 32,
id: 1
}, {
name: 'Jonny',
age: 34,
id: 2
}, {
name: 'Blake',
age: 28,
id: 3
}, {
name: 'David',
age: 35,
id: 4
}];
$scope.filter = function (value) {
$scope.filteredPeople = $filter('filter')(people, {
name: $scope.filterValue
});
}
$scope.people = people.slice(0);
Delete your $scope.filter() function in the controller and the ng-change="filter()" in your view. You should change var people array to $scope.people. You also need to delete the line $scope.people = people.slice(0);.
Create a filter function in your controller to only return people whose name property is empty if $scope.filterValue is empty:
$scope.emptyFilter = function(person) {
if ($scope.filterValue.length === 0) {
if (person.name.length === 0) {
return person;
}
} else {
return person;
}
};
Next, update your ng-repeat with the following:
<li ng-repeat="p in people | filter:emptyFilter | filter:{name: filterValue}">

Angular JS: How to apply the date range filter between two dates in one column

I am aware that it may be Duplicate Question, but I tried that too but it didnt work it. So, I am posting my Question now. My Question is Apply the Date range filter using Angular js only one column.
Here is MY code:
HTML:
<div ng-app="myApp" ng-controller="myCtrl">
<div>
<table>
<tr>
<td>Start Date</td>
<td><input type="text" name="S_Date" ng-model="startDate"/></td>
<td>End Date</td>
<td><input type="text" name="E_Date" ng-model="endDate"/>
</tr>
</table>
</div>
<table>
<tr>
<th>Date</th>.
<th>Stock</th>
</tr>
<tr ng-repeat="subject in records |myfilter:startDate:endDate">
<td>{{ subject.name * 1000|date:'dd-MM-yyyy'}}<td>
<td>{{ subject.marks }}</td>
</tr>
</table>
Angular JS:
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.records = [
{
"name" : "2016-08-01",
"marks" : 250
},{
"name" : "2016-08-02",
"marks" : 150
},{
"name" : "2016-08-03",
"marks" : 100
},{
"name" : "2016-08-04",
"marks" : 150
},{
"name" : "2016-05-01",
"marks" : 750
},{
"name" : "2016-05-02",
"marks" : 1500
},{
"name" : "2016-03-03",
"marks" : 500
},{
"name" : "2016-04-04",
"marks" : 650
}
]
function parseDate(input) {
var parts = input.split('-');
return new Date(parts[2], parts[1]-1, parts[0]);
}
app.filter("myfilter", function() {
return function(items, from1, to) {
var df = parseDate(from1);
var dt = parseDate(to);
alert(df)
alert(dt)
var result = [];
for (var i=0; i<items.length; i++){
var tf = new Date(items[i].startDate * 1000),
tt = new Date(items[i].endDate * 1000);
if (tf > df && tt < dt) {
result.push(items[i]);
}
}
return result;
};
});
});
</script>
Please advice me Where I am going wrong.Please suggest me.Thanks in advance.
I recommend you to use moment.js library: http://momentjs.com/
Here is working plunkr with your range filter: https://plnkr.co/edit/dfpsBI0uom5ZAEnDF3wM?p=info
<div ng-controller="MainCtrl">
<table>
<tr>
<td>Start Date</td>
<td>
<input type="text" name="S_Date" ng-model="startDate" />
</td>
<td>End Date</td>
<td>
<input type="text" name="E_Date" ng-model="endDate" />
</td>
</tr>
</table>
<table>
<tr>
<th>Date</th>.
<th>Stock</th>
</tr>
<tr ng-repeat="subject in records | myfilter: startDate: endDate">
<td>{{ subject.name | date:'dd-MM-yyyy'}}</td>
<td>{{ subject.marks }}</td>
</tr>
</table>
</div>
app.controller('MainCtrl', function($scope) {
$scope.startDate = "2016-08-01";
$scope.endDate = "2016-08-03";
$scope.records = [{
"name": "2016-08-01",
"marks": 250
}, {
"name": "2016-08-02",
"marks": 150
}, {
"name": "2016-08-03",
"marks": 100
}, {
"name": "2016-08-04",
"marks": 150
}, {
"name": "2016-05-01",
"marks": 750
}, {
"name": "2016-05-02",
"marks": 1500
}, {
"name": "2016-03-03",
"marks": 500
}, {
"name": "2016-04-04",
"marks": 650
}];
});
app.filter("myfilter", function($filter) {
return function(items, from, to) {
return $filter('filter')(items, "name", function(v) {
var date = moment(v);
return date >= moment(from) && date <= moment(to);
});
};
});
$scope.Customfilterobj`enter code here` = { status: "Complete",StartDate: "2017-02-01T08:00:00",EndDate: "2018-02-01T08:00:00 " };
<tr ng-repeat="dt in data | filter: {Status: Customfilterobj.status} | dateRange:Customfilterobj.StartDate:Customfilterobj.EndDate">
Here we have use two filters as below:
filter: {Status: Customfilterobj.status} work as compare "complete" value with Status of data collection.
dateRange:Customfilterobj.StartScheuleDate:Customfilterobj.EndScheuleDate" : dateRange is custom filter for compare Expiration_date between StartDate and EndDate.
app.filter('dateRange', function () {
return function (data, greaterThan, lowerThan) {
if (greaterThan != null && lowerThan != null && greaterThan != undefined && lowerThan != undefined) {
data = data.filter(function (item) {
if (item.Expiration_date != null) {
var exDate = new Date(item.Expiration_date);
return exDate >= new Date(greaterThan) && exDate <= new Date(lowerThan);
}
});
}
return data;
};
});
Adding off of Roman Koliada's plunker. His process has a small issue in the usage of the angular $filter. I have the updated here:
https://plnkr.co/edit/l4t4Fln4HhmZupbmOFki?p=preview
New filter:
app.filter("myfilter", function($filter) {
return function(items, from, to, dateField) {
startDate = moment(from);
endDate = moment(to);
return $filter('filter')(items, function(elem) {
var date = moment(elem[dateField]);
return date >= startDate && date <= endDate;
});
};
});
The issue was that the function input into $filter function was the third param, and loops over every attribute of every object in the list. Console logging his plunker calls moment() on every single attribute of every object. By instead inputting a function as the second param, as the expression instead of the comparator - we can call the comparison only on the date field.
Angular doc: https://docs.angularjs.org/api/ng/filter/filter

Bind filter in angularjs template [duplicate]

My goal is to apply a formatting filter that is set as a property of the looped object.
Taking this array of objects:
[
{
"value": "test value with null formatter",
"formatter": null,
},
{
"value": "uppercase text",
"formatter": "uppercase",
},
{
"value": "2014-01-01",
"formatter": "date",
}
]
The template code i'm trying to write is this:
<div ng-repeat="row in list">
{{ row.value | row.formatter }}
</div>
And i'm expecting to see this result:
test value with null formatter
UPPERCASE TEXT
Jan 1, 2014
But maybe obviusly this code throws an error:
Unknown provider: row.formatterFilterProvider <- row.formatterFilter
I can't immagine how to parse the "formatter" parameter inside the {{ }}; can anyone help me?
See the plunkr http://plnkr.co/edit/YnCR123dRQRqm3owQLcs?p=preview
The | is an angular construct that finds a defined filter with that name and applies it to the value on the left. What I think you need to do is create a filter that takes a filter name as an argument, then calls the appropriate filter (fiddle) (adapted from M59's code):
HTML:
<div ng-repeat="row in list">
{{ row.value | picker:row.formatter }}
</div>
Javascript:
app.filter('picker', function($filter) {
return function(value, filterName) {
return $filter(filterName)(value);
};
});
Thanks to #karlgold's comment, here's a version that supports arguments. The first example uses the add filter directly to add numbers to an existing number and the second uses the useFilter filter to select the add filter by string and pass arguments to it (fiddle):
HTML:
<p>2 + 3 + 5 = {{ 2 | add:3:5 }}</p>
<p>7 + 9 + 11 = {{ 7 | useFilter:'add':9:11 }}</p>
Javascript:
app.filter('useFilter', function($filter) {
return function() {
var filterName = [].splice.call(arguments, 1, 1)[0];
return $filter(filterName).apply(null, arguments);
};
});
I like the concept behind these answers, but don't think they provide the most flexible possible solution.
What I really wanted to do and I'm sure some readers will feel the same, is to be able to dynamically pass a filter expression, which would then evaluate and return the appropriate result.
So a single custom filter would be able to process all of the following:
{{ammount | picker:'currency:"$":0'}}
{{date | picker:'date:"yyyy-MM-dd HH:mm:ss Z"'}}
{{name | picker:'salutation:"Hello"'}} //Apply another custom filter
I came up with the following piece of code, which utilizes the $interpolate service into my custom filter. See the jsfiddle:
Javascript
myApp.filter('picker', function($interpolate ){
return function(item,name){
var result = $interpolate('{{value | ' + arguments[1] + '}}');
return result({value:arguments[0]});
};
});
One way to make it work is to use a function for the binding and do the filtering within that function. This may not be the best approach: Live demo (click).
<div ng-repeat="row in list">
{{ foo(row.value, row.filter) }}
</div>
JavaScript:
$scope.list = [
{"value": "uppercase text", "filter": "uppercase"}
];
$scope.foo = function(value, filter) {
return $filter(filter)(value);
};
I had a slightly different need and so modified the above answer a bit (the $interpolate solution hits the same goal but is still limited):
angular.module("myApp").filter("meta", function($filter)
{
return function()
{
var filterName = [].splice.call(arguments, 1, 1)[0] || "filter";
var filter = filterName.split(":");
if (filter.length > 1)
{
filterName = filter[0];
for (var i = 1, k = filter.length; i < k; i++)
{
[].push.call(arguments, filter[i]);
}
}
return $filter(filterName).apply(null, arguments);
};
});
Usage:
<td ng-repeat="column in columns">{{ column.fakeData | meta:column.filter }}</td>
Data:
{
label:"Column head",
description:"The label used for a column",
filter:"percentage:2:true",
fakeData:-4.769796600014472
}
(percentage is a custom filter that builds off number)
Credit in this post to Jason Goemaat.
Here is how I used it.
$scope.table.columns = [{ name: "June 1 2015", filter: "date" },
{ name: "Name", filter: null },
] etc...
<td class="table-row" ng-repeat="column in table.columns">
{{ column.name | applyFilter:column.filter }}
</td>
app.filter('applyFilter', [ '$filter', function( $filter ) {
return function ( value, filterName ) {
if( !filterName ){ return value; } // In case no filter, as in NULL.
return $filter( filterName )( value );
};
}]);
I improved #Jason Goemaat's answer a bit by adding a check if the filter exists, and if not return the first argument by default:
.filter('useFilter', function ($filter, $injector) {
return function () {
var filterName = [].splice.call(arguments, 1, 1)[0];
return $injector.has(filterName + 'Filter') ? $filter(filterName).apply(null, arguments) : arguments[0];
};
});
The newer version of ng-table allows for dynamic table creation (ng-dynamic-table) based on a column configuration. Formatting a date field is as easy as adding the format to your field value in your columns array.
Given
{
"name": "Test code",
"dateInfo": {
"createDate": 1453480399313
"updateDate": 1453480399313
}
}
columns = [
{field: 'object.name', title: 'Name', sortable: 'name', filter: {name: 'text'}, show: true},
{field: "object.dateInfo.createDate | date :'MMM dd yyyy - HH:mm:ss a'", title: 'Create Date', sortable: 'object.dateInfo.createDate', show: true}
]
<table ng-table-dynamic="controller.ngTableObject with controller.columns" show-filter="true" class="table table-condensed table-bordered table-striped">
<tr ng-repeat="row in $data">
<td ng-repeat="column in $columns">{{ $eval(column.field, { object: row }) }}</td>
</tr>
</table>
I ended up doing something a bit more crude, but less involving:
HTML:
Use the ternary operator to check if there is a filter defined for the row:
ng-bind="::data {{row.filter ? '|' + row.filter : ''}}"
JS:
In the data array in Javascript add the filter:
, {
data: 10,
rowName: "Price",
months: [],
tooltip: "Price in DKK",
filter: "currency:undefined:0"
}, {
This is what I use (Angular Version 1.3.0-beta.8 accidental-haiku).
This filter allows you to use filters with or without filter options.
applyFilter will check if the filter exists in Angular, if the filter does not exist, then an error message with the filter name will be in the browser console like so...
The following filter does not exist: greenBananas
When using ng-repeat, some of the values will be undefined. applyFilter will handle these issues with a soft fail.
app.filter( 'applyFilter', ['$filter', '$injector', function($filter, $injector){
var filterError = "The following filter does not exist: ";
return function(value, filterName, options){
if(noFilterProvided(filterName)){ return value; }
if(filterDoesNotExistInAngular(filterName)){ console.error(filterError + "\"" + filterName + "\""); return value; }
return $filter(filterName)(value, applyOptions(options));
};
function noFilterProvided(filterName){
return !filterName || typeof filterName !== "string" || !filterName.trim();
}
function filterDoesNotExistInAngular(filterName){
return !$injector.has(filterName + "Filter");
}
function applyOptions(options){
if(!options){ return undefined; }
return options;
}
}]);
Then you use what ever filter you want, which may or may not have options.
// Where, item => { name: "Jello", filter: {name: "capitalize", options: null }};
<div ng-repeat="item in items">
{{ item.name | applyFilter:item.filter.name:item.filter.options }}
</div>
Or you could use with separate data structures when building a table.
// Where row => { color: "blue" };
// column => { name: "color", filter: { name: "capitalize", options: "whatever filter accepts"}};
<tr ng-repeat="row in rows">
<td ng-repeat="column in columns">
{{ row[column.name] | applyFilter:column.filter.name:column.filter.options }}
</td>
</tr>
If you find that you require to pass in more specific values you can add more arguments like this...
// In applyFilter, replace this line
return function(value, filterName, options){
// with this line
return function(value, filterName, options, newData){
// and also replace this line
return $filter(filterName)(value, applyOptions(options));
// with this line
return $filter(filterName)(value, applyOptions(options), newData);
Then in your HTML perhaps your filter also requires a key from the row object
// Where row => { color: "blue", addThisToo: "My Favorite Color" };
// column => { name: "color", filter: { name: "capitalize", options: "whatever filter accepts"}};
<tr ng-repeat="row in rows">
<td ng-repeat="column in columns">
{{ row[column.name] | applyFilter:column.filter.name:column.filter.options:row.addThisToo }}
</td>
</tr>

Another Infinite $digest Loop

Doing a loop within a loop in a view:
<tr ng-repeat="result in results">
<td>
<span ng-repeat="device in helpers.getIosDevices(result.ios_device)">
{{ device.code }}
</span>
</td>
</tr>
The controller:
$scope.helpers = CRM.helpers;
The helper:
var CRM = CRM || {};
CRM.helpers = {
// Handle "111" value format
getIosDevices: function (devices) {
var obj = [];
if (devices !== null && devices !== undefined) {
if (devices.charAt(0) === '1') {
obj.push({
code: 'ipod',
name: 'iPod',
});
}
if (devices.charAt(1) === '1') {
obj.push({
code: 'ipad',
name: 'iPad',
});
}
if (devices.charAt(2) === '1') {
obj.push({
code: 'iphone',
name: 'iPhone',
});
}
}
return obj;
}
};
Got this error: https://docs.angularjs.org/error/$rootScope/infdig?p0=10&p1=%5B%5B%22fn:%E2%80%A620%20%20%7D;%20newVal:%20undefined;%20oldVal:%20undefined%22%5D%5D
as I understand but I don't know how can I solve it in my case. What workaround should I use?
The reason of this error that you try to change source list in ng-repeat directive during digest cycle.
<span ng-repeat="device in helpers.getIosDevices(result.ios_device)">
^^^^^^^^
and obj.push(/* ... */) in getIosDevices
First we need ask our self when digest cycle will stop looping: It will stop when Angular detect that on several iterations the list didn't change. In your case each time when ng-repeat calls getIosDevices method - the list gets different items and therefore it looping again till you get limit and Angular drops this exception.
So what is a solution:
In Angular its not good practice to call method getList() in ngRepeat. Because developpers make bugs.
Its clear that in your case getIosDevices() list depends on results therefore I would create different fixed object with some watcher on results and write HTML part like:
<tr ng-repeat="result in results">
<td>
<span ng-repeat="device in devices[result.ios_device]">
{{ device.code }}
</span>
</td>
</tr>
where devices represents Map.
This is some demo that might help you:
$scope.results = [{
ios_device: "100"
}, {
ios_device: "010"
}, {
ios_device: "001"
}];
$scope.devices = {
"100": [{
code: 'ipod',
name: 'iPod1',
},
{
code: 'ipod',
name: 'iPod2',
}],
"010": [{
code: 'ipod',
name: 'iPod1',
},
{
code: 'ipad',
name: 'iPad2',
}],
"001": [{
code: 'ipod',
name: 'iPod1',
},
{
code: 'iphone',
name: 'iphone2',
}],
}
HTML
<table>
<tr ng-repeat="result in results">
<td><span ng-repeat="device in devices[result.ios_device]">
{{ device.code }}
</span>
</td>
</tr>
</table>
Demo in Fiddle

Resources