【问题标题】:apply formatting filter dynamically in a ng-repeat在 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”字符串

标签: javascript angularjs dynamic filter


【解决方案1】:

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

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

感谢@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>
            

            【讨论】:

              猜你喜欢
              • 2016-06-16
              • 1970-01-01
              • 2015-06-21
              • 2014-07-29
              • 2015-10-20
              • 1970-01-01
              • 2013-01-07
              • 2019-07-12
              相关资源
              最近更新 更多