Dynamically add filter in ng-repeat

846 Views Asked by At

I am building a table where the rows and columns are built entirely based on the data that is sent to it.

I'm very close to having it work, I'm having trouble figuring out how to build a custom filter and pass in the filter patterns dynamically

The object that makes up the columns looks like

{ name: 'transactionDate', displayName: 'Date / Time', displayOrder: 1, filter: "date: 'MM/dd/yy hh:mm a'" }

The object that makes up the transaction for the rows looks like this:

{ transactionDate: '2015-06-11', transactionType: 'This Type', transactionAmount: 25 }

The HTML I have is this:

<td ng-repeat="col in columns">{{transaction[col.name] | dynamicFilter: col.filter}}</td>

The filter I currently have built is:

function dynamicFilter($filter) {
    return function (value, filter) {
        console.log(filter);
        console.log(value);
        var test = $filter(filter)(value);
        return test;
    }
}

Both filter and value are getting passed correctly. I'm having trouble figuring out how to apply the filter to the value before returning. A value that might be passed in would 2015-06-10T16:17:14 be and a filter that would be passed in could be date: 'MM/dd/yy hh:mm a' to create date/time filter. Or 21 and currency for a dollar value.

I would like to be able to use Angular's built in features in a similar way you could on the view

2

There are 2 best solutions below

2
On BEST ANSWER

For these dynamic filters that have partial params (such as the format you're providing with date), you have to remove the param from the filter and apply it later.

So filter: "date: 'MM/dd/yy hh:mm a'", needs to be just filter: "date".

The additional constraint, MM/dd/yy hh:mm a, would be sent along with the value $filter(filter)(value, 'MM/dd/yy hh:mm a');

To do this generically, you can take advantage of apply. The Object can be:

{filter: { type: "date", params: ['MM/dd/yy hh:mm a'] } }

And the directive can have (assuming you send the params as well):

var filterFn = $filter(filter.type); 
return filterFn.apply(filterFn, [value].concat(filter.params));

EDIT: here's a JSFiddle with two buttons, the first demonstrates your original approach with "date: 'MM/dd/yy hh:mm a'", and the second demonstrates applied approach that I outline above http://jsfiddle.net/4whemakt/

4
On

You can apply and return the filtered value conditionally in your dynamicFilter. Something like this

function dynamicFilter($filter) {
    return function (value, filter) {
        if (filter.indexOf('date:') !== -1) {
           //Note: I am using moment js to format the date
           return moment(value).format(filter.match(/'([^']+)'/)[1]);
        }
        else {
            return $filter(filter)(value)
        }
    }
}

moment.js reference http://momentjs.com/