在 ng-repeat 中动态应用格式化过滤器
Posted
技术标签:
【中文标题】在 ng-repeat 中动态应用格式化过滤器【英文标题】:apply formatting filter dynamically in a ng-repeat 【发布时间】:2014-02-24 20:05:18 【问题描述】:我的目标是应用设置为循环对象属性的格式过滤器。
获取这个对象数组:
[
"value": "test value with null formatter",
"formatter": null,
,
"value": "uppercase text",
"formatter": "uppercase",
,
"value": "2014-01-01",
"formatter": "date",
]
我要写的模板代码是这样的:
<div ng-repeat="row in list">
row.value | row.formatter
</div>
我期待看到这个结果:
test value with null formatter
UPPERCASE TEXT
Jan 1, 2014
但很明显,这段代码可能会引发错误:
Unknown provider: row.formatterFilterProvider <- row.formatterFilter
我无法想象如何解析 ; 中的“格式化程序”参数;谁能帮帮我?
见 plunkr http://plnkr.co/edit/YnCR123dRQRqm3owQLcs?p=preview
【问题讨论】:
很抱歉,我的帖子可能不清楚:我不需要 filter 数组。我需要根据“formater”属性格式化“value”字符串。 【参考方案1】:|
是一个 Angular 构造,它找到具有该名称的已定义过滤器并将其应用于左侧的值。我认为您需要做的是创建一个以过滤器 name 作为参数的过滤器,然后调用适当的过滤器(fiddle)(改编自 M59 的代码):
html:
<div ng-repeat="row in list">
row.value | picker:row.formatter
</div>
app.filter('picker', function($filter)
return function(value, filterName)
return $filter(filterName)(value);
;
);
感谢@karlgold 的评论,这是一个支持参数的版本。第一个示例使用add
过滤器直接将数字添加到现有数字,第二个示例使用useFilter
过滤器按字符串选择add
过滤器并将参数传递给它(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);
;
);
【讨论】:
好主意!让我感到奇怪的是,Angular 核心中还不存在。 我认为目前这是最好的方法,比 m59 的方法更优雅——当然也可以。正如你所说,“row.formatter”是一个字符串,应该是一个函数名来让代码工作;如果没有解决方案将其解析为函数,这似乎是唯一的解决方法。谢谢大家! 支持过滤器规范参数(例如日期格式或小数位数)的稍微花哨的版本:plnkr.co/edit/tCPMjl?p=preview 并添加` ||以var filterName
开头的行末尾的“过滤器”处理未定义过滤器的情况。
这会从arguments
数组中删除filterName
,以便将其余参数传递给下一行的过滤器调用。【参考方案2】:
我喜欢这些答案背后的概念,但不认为它们提供了最灵活的解决方案。
我真正想做的并且我相信有些读者会有同样的感受,就是能够动态地传递一个过滤器表达式,然后它会评估并返回适当的结果。
因此,单个自定义过滤器将能够处理以下所有内容:
ammount | picker:'currency:"$":0'
date | picker:'date:"yyyy-MM-dd HH:mm:ss Z"'
name | picker:'salutation:"Hello"'
//应用另一个自定义过滤器
我想出了以下代码,它将$interpolate
服务用于我的自定义过滤器。见jsfiddle:
Javascript
myApp.filter('picker', function($interpolate )
return function(item,name)
var result = $interpolate('value | ' + arguments[1] + '');
return result(value:arguments[0]);
;
);
【讨论】:
这是符合我目的的答案。如果没有过滤器名称,我只会在该项目中添加一个返回。这样做的重点是尽可能动态。不过谢谢!【参考方案3】:使其工作的一种方法是使用绑定函数并在该函数中进行过滤。这可能不是最好的方法: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);
;
【讨论】:
谢谢,但这不是我要找的。我想格式化“值”字符串作为格式化程序给出“过滤器”值。请看一下plunkr。 @user3259152 我更新了一个解决方案。我会继续调查。【参考方案4】:我的需求略有不同,因此稍微修改了上面的答案($interpolate
解决方案达到了相同的目标,但仍然有限):
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);
;
);
用法:
<td ng-repeat="column in columns"> column.fakeData | meta:column.filter </td>
数据:
label:"Column head",
description:"The label used for a column",
filter:"percentage:2:true",
fakeData:-4.769796600014472
(percentage
是基于number
构建的自定义过滤器)
【讨论】:
【参考方案5】:本文感谢 Jason Goemaat。
这是我的使用方法。
$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】:我通过添加检查过滤器是否存在来稍微改进@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】:较新版本的 ng-table 允许基于列配置创建动态表 (ng-dynamic-table)。格式化日期字段就像将格式添加到列数组中的字段值一样简单。
给定
"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】:我最终做了一些更粗略但涉及较少的事情:
HTML:
使用三元运算符检查是否有为该行定义的过滤器:
ng-bind="::data row.filter ? '|' + row.filter : ''"
JS:
在 Javascript 中的数据数组中添加过滤器:
,
data: 10,
rowName: "Price",
months: [],
tooltip: "Price in DKK",
filter: "currency:undefined:0"
,
【讨论】:
【参考方案9】:这是我使用的(Angular 版本 1.3.0-beta.8 意外俳句)。
此过滤器允许您使用带有或不带有过滤器选项的过滤器。
applyFilter 会检查 Angular 中是否存在过滤器,如果过滤器不存在,则会在浏览器控制台中显示带有过滤器名称的错误消息...
以下过滤器不存在:greenBananas
当使用 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;
]);
然后你使用你想要的任何过滤器,它可能有也可能没有选项。
// 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>
或者您可以在构建表格时使用单独的数据结构。
// 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>
如果您发现需要传递更具体的值,您可以添加更多这样的参数...
// 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);
那么在您的 HTML 中,您的过滤器可能还需要来自 row 对象的键
// 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>
【讨论】:
以上是关于在 ng-repeat 中动态应用格式化过滤器的主要内容,如果未能解决你的问题,请参考以下文章
按日期范围过滤ng-repeat(dd / MM / yyyy HH:mm格式)
Angular js - 如果 ng-repeat 为空则显示消息