apply formatting filter dynamically in a ng-repeat

47,933

Solution 1

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);
    };
});

Solution 2

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]});
    };
});

Solution 3

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);
};
Share:
47,933
IcedBlind
Author by

IcedBlind

Updated on July 14, 2022

Comments

  • IcedBlind
    IcedBlind almost 2 years

    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