Angular date range filter - angularjs

I was wondering if anyone could help me. I'm currently trying to get a date filter to work in Angular. I could be going about this completely the wrong way but just thought I would ask.
I currently have an ng-repeat looping through an array of objects. My objects have the following fields: title, sentBy and recevied. Received is in UTC format and my filter basically takes two inputs also in utc format for start and end date. The filter then checked if the received is greater than or equal to to start date or less than or equal to the end date. My issue is that the input to the filter is the input of the whole object. Im not sure how to access the received field of the object within the filter to do the comparrison. I tried input.received but it didnt seem to work. heres a sample of my code.
.filter('dateRange', function(){
return function(input, startDate, endDate) {
if(input.received >= startDate && input <= endDate){
return input;
}
};
})
As I say I could be going about this completely wrong but any help would be greatly appreciated.
edit:
my html code is as simple as below:
<div ng-repeat="message in messages | dateRange: startDate : endDate " >

Try below code. You need to compare the time.
.filter('dateRange', function(){
return function(input, startDate, endDate) {
angular.forEach(input, function(obj){
if(obj.received.getTime() >= startDate.getTime() && obj.received.getTime() <= endDate.getTime()) {
return obj;
}
});
};
});
<div ng-bind="messages | dateRange: startDate : endDate " ></div>
or
<div> {{messages | dateRange: startDate : endDate }}</div>

In your code the filter is working on messages array, that means the first argument (input) is the array, and the return type has to be an array too. Have a look here.
Your code should be something like that:
<div ng-repeat="message in messages | dateRange: startDate : endDate" >
Your filter is:
.filter('dateRange', function() {
return function(input, startDate, endDate) {
var retArray = [];
angular.forEach(input, function(obj){
var receivedDate = obj.received;
if(receivedDate >= startDate && receivedDate <= endDate) {
retArray.push(obj);
}
});
return retArray;
};
});
Here is a plunker.

Related

Date filter causes ng-repeat+other filters to be extremely slow in IE11

I have an ng-repeat plus some custom filters, and a date range filter, all works wonderful in Chrome, Mozilla, android. But in IE with the Date Range filter everything grinds to a halt. The filters take 10 seconds to register (I have filters tied to checkboxes and free text), with the checkbox animations also lagging until the data loads. If I remove the date range filter then everything is fine in IE.
The list is called from an azure API, the list is currently 8500 records long, but the length can't be avoided, and all runs smooths with the size apart from IE and the date range function.
I've tried something to speed it up in IE such as adding :: single binding to all {{ }} values.
I am also using pagination and have LimitTo set to 20
But these fixes seem to be if ng-repeat and filters are slow in IE8+ in general, but mine is fine with the other filters its only with the date range.
The repeat:
<div class="inner" ng-repeat="app in displayedData = ( applications
| orderBy: sortType:sortReverse
| filter: FAl
| filterStatus: FStatus
| filterStage: FStage
| dateRange: startDate:endDate
) | start: (currentPage - 1) * perPage | limitTo: perPage">
<div class="record" ng-class-odd="'odd odd-Record'" ng-class-even="'even even-Record'" data-toggle="collapse" data-target="#{{ app.Id }}">
<div class="field field-Name">{{ app.Lastname }}</div>
<div class="field field-AccountNumber">{{ app.AccountNumber }}</div>
<div class="field field-AppDate">{{ app.DateApplied | date : "dd/MM/yyyy"}}</div>
</div>
The date range filter:
//Filter: Dates
App.filter('dateRange', function () {
return function (applications, startDate, endDate) {
var filtered = [];
var start_date = startDate.toString();
var end_date = endDate.toString();
angular.forEach(applications, function (value) {
if (Date.parse(value.DateApplied) > Date.parse(start_date) && Date.parse(value.DateApplied) < Date.parse(end_date)) {
filtered.push(value);
}
});
return filtered;
};
});
The values for the date range are sent from pikaday date picker:
<h4>Date Range</h4>
<div>
<label style="font-weight: 500">Start Date</label>
<input style="float: right; width: 128px;" type="text" id="datepickerStartDate" ng-model="startDate">
</div>
<div>
<label style="float: left; font-weight: 500">End Date</label>
<input style="float: right; width: 128px;" type="text" id="datepickerEndDate" ng-model="endDate">
</div>
The other filters are all in the below format just passed different specific field values.
//Filter: Status
App.filter('filterStatus', function () {
return function (applications, Status) {
var items = {
status: Status,
out: []
};
angular.forEach(applications, function (value, key) {
if (this.status[value.Status] === true) {
this.out.push(value);
}
}, items);
return items.out;
};
});
First, this is what you should have in html. Move all filtering to controller function - then you can test it, test perfomance, etc.
<div class="inner" ng-repeat="app in displayedData">
...
Second, prepare your data. If your backend return dates as strings (Cant guess what this is about though), parse them as you get them. Quite evident that parsing dates from string is much slower than comparing two date.
Issue was cased by having an && criteria in the date range function if statement
Trouble shooting through it, I found having having only one thing to check for in the IF stopped all slowness.
I instead created a filter for start and end date separately
App.filter('startDate', function () {
return function (applications, startDate) {
var items = {
startdate: startDate,
out: []
};
angular.forEach(applications, function (value, key) {
if (Date.parse(value.DateApplied) > Date.parse(this.startdate)) {
this.out.push(value);
}
}, items);
return items.out;
};
});
App.filter('endDate', function () {
return function (applications, endDate) {
var items = {
enddate: endDate,
out: []
};
angular.forEach(applications, function (value, key) {
if (Date.parse(value.DateApplied) < Date.parse(this.enddate)) {
this.out.push(value);
}
}, items);
return items.out;
};
});
This has fixed the immense slowness experienced in IE. I am sadly unsure why this was causing an issue.

st-table convert string to date

I have json object array binded to a table. Objects have a date column which is in date format but string. I need to change date format.
I tried;
<tbody>
<tr ng-repeat="row in table_data">
<td>{{row.availabledate | date:'MMMM dd, yyyy'}}</td>
</tr>
</tbody>
But, since it is string it is not formatted. I dont want to convert it in a loop for the sake of performance. Is there a way to convert this string to date and then format it on html part?
One way is to make your own filter, then use the date filter.
This crude/raw filter expects a YYYYMMDD string and creates a date object from it that you can then use angular's date filter on.
app.filter('strToDate', function() {
return function(input) {
var year = input.substring(0,4);
var month = input.substring(4,6);
var day = input.substring(6,8);
// Do filter work here
return new Date(year,month,day);
}
});
and then
<td>{{row.availabledate | strToDate | date:'MMMM dd, yyyy'}}</td>
Here's a Plunker link with working example: https://plnkr.co/edit/hn5StpktiMLq2gWHAszu?p=preview
You could also just make your filter return the formatted date.
Another way, doing all the work inside the filter:
app.filter('strToDate', function($filter) {
//1. date value
//2. the format input by user
return function(input, format) {
//Create the date object
var year = input.substring(0,4);
var month = input.substring(4,6);
var day = input.substring(6,8);
var newDate = new Date(year,month,day);
// return the format selected
return $filter('date')(newDate , format)
}
});
You can use the filter like this:
<td>{{row.availabledate | strToDate :'MMMM dd, yyyy'}}</td>

How to display date in different formats in ng-repeat - angularjs

I have a date as "2017-04-03 05:00:07". I need to check for the date is today's date. If it is today's date i need to display as today or time.
If it is yesterday's need to display as yesterday or date as "MMM dd"
If it is last month or with in this year then, "MMM dd".
If it is last year then dd/mm/yyyy
I tried to display like this using a directive but this is not working for me.
Is there anyother way?
app.directive('myDirective', function($filter) {
return {
restrict: "A",
scope: {
myDirective: '='
},
link: function(scope, element, attrs) {
var date1 = new Date(scope.myDirective.updateddate);
var date2 = new Date();
var timeDiff = Math.abs(date2.getTime() - date1.getTime());
var diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24));
if (diffDays == 1) {
scope.myDirective.updateddate = 'yesterday'
} else if (diffDays > 2 && diffDays <= 365) {
scope.myDirective.updateddate = $filter('date') scope.myDirective.updateddate, 'dd-MMM');
}
else if (diffDays > 365) {
scope.myDirective.updateddate = $filter('date') scope.myDirective.updateddate, 'dd-MM-YYYY');
} });
Use Moment.js while displaying like
{{moment(date).calendar()}} // Today at 11:17 AM
For reference: https://momentjs.com/
Using a custom filter is the most correct approach to this.
You define a filter much like a directive:
app.filter('myfilternamehere', function() {
return function(input) {
//do some stuff that creates the correct output
return output;
}
});
I have created a JSFiddle that might contain a solution for your problem and at the same time shows you how to create a custom directive in a bit more detail.

problems with a filter date in angularJS

i have a problems with my filter date , I would like to filter between 2 date but with a condition if the date from is not valid then I start at 2017-01-01 (for that I think it is good) and if the date 'to' is not valid I start Has the current date
Here is my plunker:
http://plnkr.co/edit/8sK29zG7YoPOdntbFfcK?p=preview
Thank you for your help
Your filter could be something like this :
app.filter("myfilter", function($filter) {
return function(items, from, to) {
const testFrom = Date.parse(from);
const testTo = Date.parse(to);
if (!testFrom){
console.log('Not valid');
from = moment('2017-01-01');
}
//here it does nt work
if (!testTo){
to = moment();
}
const valids = items.reduce((acc,val) => {
const date = moment(val.dateenvoi);
if(date.isSameOrAfter(from) && date.isSameOrBefore(to))
acc.push(val)
return acc;
},[]);
return valids;
};
});
Check this
No need for custom filter for this functionality, you can use angular predefined filter for this like
<input type="text" name="S_Date" ng-model="filter.dateenvoi"/>
and
<tr ng-repeat="x in myData | filter: filter">
working Plunker

angular ui bootstrap datepicker filter with repeater

i am new to angularjs and i am getting problem at the repeat filter with bootstrap date-picker ng-model (dt | date:'yyyy-MM-dd') with date (create_at).
<li ng-repeat="item in items | filter:{create_at:{'dt| date:"yyyy-MM-dd"'}, subject:query}" class="thumbnail">
...
</li>
Thanks!
you need to create a custom filter for that, the date filter is a formatter, it will not filter your results so what you need to do is something like: (this is for date range but you can convert it to a single date):
app.filter("dateRange", function() {
return function(items, from, to) {
var df = parseDate(from);
var dt = parseDate(to);
var result = [];
for (var i=0; i<items.length; i++){
var tf = new Date(items[i].date1 * 1000),
tt = new Date(items[i].date2 * 1000);
if (tf > df && tt < dt) {
result.push(items[i]);
}
}
return result;
};
in view:
<lin g-repeat="order in orders | dateRange:dateFrom:dateTo">
...
</li>
so you see here, we get a date string, convert it to a date and then filter by the date range. you can modify it as you please... you can also turn dates to ISO or whatever

Resources