在ng-repeat中动态应用格式化过滤器

时间:2022-11-25 18:15:08

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?

我不能immagine如何解析里面的“格式化程序”参数{ { } };谁能帮我吗?

See the plunkr http://plnkr.co/edit/YnCR123dRQRqm3owQLcs?p=preview

看到plunkr http://plnkr.co/edit/YnCR123dRQRqm3owQLcs?p=preview

9 个解决方案

#1


56  

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):

|是一个角构形,它查找具有该名称的已定义过滤器,并将其应用到左边的值。我认为您需要做的是创建一个过滤器,以过滤器名称作为参数,然后调用适当的过滤器(fiddle)(改编自M59的代码):

HTML:

HTML:

<div ng-repeat="row in list">
    {{ row.value | picker:row.formatter }}
</div>

Javascript:

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):

由于@karlgold的评论,这是一个版本,它支持论点。第一个例子使用直接添加过滤器将号码添加到现有数量和第二个使用useFilter过滤器选择通过字符串并将参数传递给它添加过滤器(小提琴):

HTML:

HTML:

<p>2 + 3 + 5 = {{ 2 | add:3:5 }}</p>
<p>7 + 9 + 11 = {{ 7 | useFilter:'add':9:11 }}</p>

Javascript:

Javascript:

app.filter('useFilter', function($filter) {
    return function() {
        var filterName = [].splice.call(arguments, 1, 1)[0];
        return $filter(filterName).apply(null, arguments);
    };
});

#2


13  

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'}}

{ { |选择供方确认:“货币:“$”:0 ' } }

{{date | picker:'date:"yyyy-MM-dd HH:mm:ss Z"'}}

{ { |日期选择器:“日期:“yyyy-MM-dd HH:mm:ss Z”} }

{{name | picker:'salutation:"Hello"'}} //Apply another custom filter

{{名称| picker:'致敬:' Hello '} //应用另一个自定义过滤器

I came up with the following piece of code, which utilizes the $interpolate service into my custom filter. See the jsfiddle:

我想到了下面这段代码,它利用了$插补服务到我的自定义过滤器中。看到jsfiddle:

Javascript

Javascript

myApp.filter('picker', function($interpolate ){
    return function(item,name){
       var result = $interpolate('{{value | ' + arguments[1] + '}}');
       return result({value:arguments[0]});
    };
});

#3


5  

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:

JavaScript:

$scope.list = [
  {"value": "uppercase text", "filter": "uppercase"}
];
$scope.foo = function(value, filter) {
  return $filter(filter)(value);
};

#4


0  

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)

(百分数是一个自定义的过滤器,用于构建数字)

#5


0  

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

#6


0  

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:

我改善@Jason Goemaat的回答有点通过添加检查过滤器是否存在,如果不返回第一个参数的默认值:

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

#7


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.

新版本的ng-table支持基于列配置的动态表创建(ng- dynamictable)。格式化日期字段就像在列数组中向字段值添加格式一样简单。

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>

#8


0  

I ended up doing something a bit more crude, but less involving:

最后我做了一些更粗糙的事情,但不太涉及:

HTML:

HTML:

Use the ternary operator to check if there is a filter defined for the row:

使用三元运算符检查是否有为行定义的过滤器:

ng-bind="::data {{row.filter ? '|' + row.filter : ''}}"

JS:

JS:

In the data array in Javascript add the filter:

在Javascript的数据数组中添加过滤器:

, {
        data: 10,
        rowName: "Price",
        months: [],
        tooltip: "Price in DKK",
        filter: "currency:undefined:0"
    }, {

#9


0  

This is what I use (Angular Version 1.3.0-beta.8 accidental-haiku).

这就是我使用的(角度版本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...

applyFilter会检查这个过滤器是否存在角度,如果这个过滤器不存在,那么一个带有过滤器名称的错误消息将会出现在浏览器控制台中……

The following filter does not exist: greenBananas

下面的过滤器不存在:greenBananas。

When using ng-repeat, some of the values will be undefined. applyFilter will handle these issues with a soft fail.

当使用ng-repeat时,一些值将是未定义的。applyFilter将用一个软失败来处理这些问题。

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

然后在你的HTML也许你的过滤器还需要一个关键对象的行

// 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>

#1


56  

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):

|是一个角构形,它查找具有该名称的已定义过滤器,并将其应用到左边的值。我认为您需要做的是创建一个过滤器,以过滤器名称作为参数,然后调用适当的过滤器(fiddle)(改编自M59的代码):

HTML:

HTML:

<div ng-repeat="row in list">
    {{ row.value | picker:row.formatter }}
</div>

Javascript:

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):

由于@karlgold的评论,这是一个版本,它支持论点。第一个例子使用直接添加过滤器将号码添加到现有数量和第二个使用useFilter过滤器选择通过字符串并将参数传递给它添加过滤器(小提琴):

HTML:

HTML:

<p>2 + 3 + 5 = {{ 2 | add:3:5 }}</p>
<p>7 + 9 + 11 = {{ 7 | useFilter:'add':9:11 }}</p>

Javascript:

Javascript:

app.filter('useFilter', function($filter) {
    return function() {
        var filterName = [].splice.call(arguments, 1, 1)[0];
        return $filter(filterName).apply(null, arguments);
    };
});

#2


13  

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'}}

{ { |选择供方确认:“货币:“$”:0 ' } }

{{date | picker:'date:"yyyy-MM-dd HH:mm:ss Z"'}}

{ { |日期选择器:“日期:“yyyy-MM-dd HH:mm:ss Z”} }

{{name | picker:'salutation:"Hello"'}} //Apply another custom filter

{{名称| picker:'致敬:' Hello '} //应用另一个自定义过滤器

I came up with the following piece of code, which utilizes the $interpolate service into my custom filter. See the jsfiddle:

我想到了下面这段代码,它利用了$插补服务到我的自定义过滤器中。看到jsfiddle:

Javascript

Javascript

myApp.filter('picker', function($interpolate ){
    return function(item,name){
       var result = $interpolate('{{value | ' + arguments[1] + '}}');
       return result({value:arguments[0]});
    };
});

#3


5  

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:

JavaScript:

$scope.list = [
  {"value": "uppercase text", "filter": "uppercase"}
];
$scope.foo = function(value, filter) {
  return $filter(filter)(value);
};

#4


0  

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)

(百分数是一个自定义的过滤器,用于构建数字)

#5


0  

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

#6


0  

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:

我改善@Jason Goemaat的回答有点通过添加检查过滤器是否存在,如果不返回第一个参数的默认值:

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

#7


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.

新版本的ng-table支持基于列配置的动态表创建(ng- dynamictable)。格式化日期字段就像在列数组中向字段值添加格式一样简单。

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>

#8


0  

I ended up doing something a bit more crude, but less involving:

最后我做了一些更粗糙的事情,但不太涉及:

HTML:

HTML:

Use the ternary operator to check if there is a filter defined for the row:

使用三元运算符检查是否有为行定义的过滤器:

ng-bind="::data {{row.filter ? '|' + row.filter : ''}}"

JS:

JS:

In the data array in Javascript add the filter:

在Javascript的数据数组中添加过滤器:

, {
        data: 10,
        rowName: "Price",
        months: [],
        tooltip: "Price in DKK",
        filter: "currency:undefined:0"
    }, {

#9


0  

This is what I use (Angular Version 1.3.0-beta.8 accidental-haiku).

这就是我使用的(角度版本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...

applyFilter会检查这个过滤器是否存在角度,如果这个过滤器不存在,那么一个带有过滤器名称的错误消息将会出现在浏览器控制台中……

The following filter does not exist: greenBananas

下面的过滤器不存在:greenBananas。

When using ng-repeat, some of the values will be undefined. applyFilter will handle these issues with a soft fail.

当使用ng-repeat时,一些值将是未定义的。applyFilter将用一个软失败来处理这些问题。

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

然后在你的HTML也许你的过滤器还需要一个关键对象的行

// 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>