4

I am trying to implement a custom filter that returns items that have a 'completed_date' between two date ranges.

However, I am finding that I need access to $scope inside my filter in order to grab the two dates 'picked' from the datepickers.

I don't think I can use an ng-change function as I have multiple other filters, and therefore need to ensure they all work together.

<select ng-model="userSelect" ng-options="user.id as user.name in usersObj"></select>

<select ng-model="departmentSelect" ng-options="department.id as department.name in deptObj"></select>

<div ng-repeat="post in postsList | dateRange | filter: {user_id: userSelect || undefined}: true | filter: {department_id: departmentSelect || undefined}: true">...</div>

The two datepickers are as follows:

<input type="date" ng-model="to_date">
<input type="date" ng-model="from_date">

And my filter in my controller;

.filter('dateRange', function() {
        return function( items ) {
            var filtered = [];
            var from_date = Date.parse($scope.from_date);
            var to_date = Date.parse($scope.to_date);
            angular.forEach(items, function(item) {
                if(item.completed_date > from_date && item.completed_date < to_date) {
                    filtered.push(item);
                }
            });
            return filtered;
        };
    });

However, I now realise I do not have access to $scope inside my filter, which leads me to think there is a better way of doing this.

Thanks in advance.

DJC
  • 1,175
  • 1
  • 15
  • 39

2 Answers2

8

As well as I can analyze your problem. You dont need $scope in your custom filter. Thats why its a custom filter do whatever you want. :)

You just need to pass the models with the filter as parameters, Like

.filter('dateRange', function() {
        return function( items, fromDate, toDate ) {
            var filtered = [];
            //here you will have your desired input
            console.log(fromDate, toDate);
            var from_date = Date.parse(fromDate);
            var to_date = Date.parse(toDate);
            angular.forEach(items, function(item) {
                if(item.completed_date > from_date && item.completed_date < to_date) {
                    filtered.push(item);
                }
            });
            return filtered;
        };
    });

And then use it in your HTML like this.

<div ng-repeat="post in postsList | dateRange : from_date : to_date | filter: {user_id: userSelect || undefined}: true | filter: {department_id: departmentSelect || undefined}: true">...</div>

Hope it helps.

M. Junaid Salaat
  • 3,765
  • 1
  • 23
  • 25
  • Hope you can update your code to convert `fromDate` & `toDate` into date objects. Because it may not work in case if those are directly passed to your filter in a string format as this problem needs. By the way its good to pass on as parameters. – Ankit Pundhir Mar 22 '16 at 12:52
  • @ankitPundhir Its not any other value. Its the same thing which is binded to the input `ng-model`. We just have passed the same model into the custom filter which is view able in your controller. You can do any thing with the model in the custom filter. – M. Junaid Salaat Mar 22 '16 at 12:56
  • it works if i select one day before in fromdate and one day more in todate but if i select the same day in both cases (fromdate and todate) it doesnt show anything, i think is because of the hour ( i have this format: 2016-11-03T08:52:50.932Z). I also had to add Date.parse in item.completed_date : Date.parse(item.completed_date)... any solution ? because now if i want dates between 2-11-2016 and 2-11-2016 i have to select in my input dates 1-11-2016 and 3-11-2016 and i want to select in both cases 2-11-2016 – Charly Nov 08 '16 at 07:56
  • Hi can you please help me to resolve similar issue. http://stackoverflow.com/a/43972873/6756805 – Hema May 15 '17 at 07:55
1

Every time you apply a new filter you tell the AngularJS Engine to run $digest which leads to poor performance.

To improve your performance and solve your issues I would suggestion using your filters in the controller, which would make your HTML more readable and likely solve your issue.

EDIT:

Above you have registered your filter to your angular app, not the controller itself. You can use the $filter object in your controller like this:

myApp.filter('dateRange',function(){ ... });

myApp.controller('CtrlName',['$filter', $filter, function(){
    var fromDate = ...;
    var toDate = ...;
    var data = [{ completed_date: ... }, ... ];
    $scope.myArray = $filter('dateRange')(data, fromDate, toDate);
}]);
cani
  • 91
  • 7
  • Could you post some code please? Not sure how my filter is 'not' in the controller? – DJC Mar 22 '16 at 13:01
  • Thanks for the edit. In my case - the app only has one controller - this page is part of a bigger project not using angular (not ideal I know), so would your approach still make any difference? Upvoted for the extra info by the way – DJC Mar 22 '16 at 15:06
  • 1
    If its just being used a single place, then it probably would not have that big of an impact on your overall performance, but it is always good to follow Best Practices whenever possible. – cani Mar 23 '16 at 08:46