aplicar filtro de formateo dinámicamente en ng-repeat

Mi objective es aplicar un filtro de formato que se establece como una propiedad del objeto en bucle.

Tomando esta matriz de objetos:

[ { "value": "test value with null formatter", "formatter": null, }, { "value": "uppercase text", "formatter": "uppercase", }, { "value": "2014-01-01", "formatter": "date", } ] 

El código de la plantilla que bash escribir es este:

 
{{ row.value | row.formatter }}

Y espero ver este resultado :

 test value with null formatter UPPERCASE TEXT Jan 1, 2014 

Pero quizás obviamente este código arroja un error:

 Unknown provider: row.formatterFilterProvider <- row.formatterFilter 

No puedo imaginar cómo analizar el parámetro “formateador” dentro de {{}}; ¿Alguien puede ayudarme?

Ver el plunkr http://plnkr.co/edit/YnCR123dRQRqm3owQLcs?p=preview

El | es una construcción angular que encuentra un filtro definido con ese nombre y lo aplica al valor de la izquierda. Lo que creo que debes hacer es crear un filtro que tome un nombre de filtro como argumento, y luego llame al filtro apropiado (violín) (adaptado del código de M59):

HTML:

 
{{ row.value | picker:row.formatter }}

Javascript:

 app.filter('picker', function($filter) { return function(value, filterName) { return $filter(filterName)(value); }; }); 

Gracias al comentario de @ karlgold, aquí hay una versión que admite argumentos. El primer ejemplo usa el filtro de add directamente para agregar números a un número existente y el segundo usa el filtro useFilter para seleccionar el filtro de add por cadena y pasarle argumentos (violín) :

HTML:

 

2 + 3 + 5 = {{ 2 | add:3:5 }}

7 + 9 + 11 = {{ 7 | useFilter:'add':9:11 }}

Javascript:

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

Me gusta el concepto detrás de estas respuestas, pero no creo que proporcionen la solución más flexible posible.

Lo que realmente quería hacer y estoy seguro de que algunos lectores sentirán lo mismo, es poder pasar dinámicamente una expresión de filtro, que luego evaluaría y devolvería el resultado apropiado.

Entonces, un solo filtro personalizado podría procesar todo lo siguiente:

{{ammount | picker:'currency:"$":0'}}

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

{{name | picker:'salutation:"Hello"'}} {{name | picker:'salutation:"Hello"'}} // Aplicar otro filtro personalizado

Se me ocurrió la siguiente pieza de código, que utiliza el servicio $interpolate en mi filtro personalizado. Ver el jsfiddle :

Javascript

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

Una forma de hacerlo funcionar es usar una función para el enlace y filtrar dentro de esa función. Este puede no ser el mejor enfoque: demostración en vivo (clic).

 
{{ foo(row.value, row.filter) }}

JavaScript:

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

Tenía una necesidad ligeramente diferente y, por lo tanto, modifiqué un poco la respuesta anterior (la solución de $interpolate alcanza el mismo objective pero sigue siendo limitada):

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

Uso:

 {{ column.fakeData | meta:column.filter }} 

Datos:

  { label:"Column head", description:"The label used for a column", filter:"percentage:2:true", fakeData:-4.769796600014472 } 

( percentage es un filtro personalizado que genera number )

Crédito en este post a Jason Goemaat.

Así es como lo usé.

 $scope.table.columns = [{ name: "June 1 2015", filter: "date" }, { name: "Name", filter: null }, ] etc...  {{ column.name | applyFilter:column.filter }}  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 ); }; }]); 

Mejoré un poco la respuesta de @Jason Goemaat al agregar un cheque si el filtro existe, y si no, devuelvo el primer argumento por defecto:

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

La versión más nueva de ng-table permite la creación dinámica de tablas (ng-dynamic-table) basada en una configuración de columna. Formatear un campo de fecha es tan fácil como agregar el formato al valor de su campo en su matriz de columnas.

Dado

 { "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} ] 
{{ $eval(column.field, { object: row }) }}

Terminé haciendo algo un poco más crudo, pero menos involucrado:

HTML:

Utilice el operador ternario para verificar si hay un filtro definido para la fila:

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

JS:

En la matriz de datos en Javascript, agregue el filtro:

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

Esto es lo que uso (Versión Angular 1.3.0-beta.8 accidental-haiku).

Este filtro le permite usar filtros con o sin opciones de filtro.

applyFilter verificará si el filtro existe en Angular, si el filtro no existe, entonces aparecerá un mensaje de error con el nombre del filtro en la consola del navegador como tal …

El siguiente filtro no existe: greenBananas

Cuando se usa ng-repeat , algunos de los valores estarán indefinidos. applyFilter manejará estos problemas con un error suave.

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

Luego usa el filtro que desee, que puede o no tener opciones.

 // Where, item => { name: "Jello", filter: {name: "capitalize", options: null }}; 
{{ item.name | applyFilter:item.filter.name:item.filter.options }}

O puede usarlo con estructuras de datos separadas al construir una tabla.

 // Where row => { color: "blue" }; // column => { name: "color", filter: { name: "capitalize", options: "whatever filter accepts"}};   {{ row[column.name] | applyFilter:column.filter.name:column.filter.options }}   

Si encuentra que necesita pasar más valores específicos, puede agregar más argumentos como este …

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

Luego, en su HTML, quizás su filtro también requiera una clave del objeto fila

 // Where row => { color: "blue", addThisToo: "My Favorite Color" }; // column => { name: "color", filter: { name: "capitalize", options: "whatever filter accepts"}};   {{ row[column.name] | applyFilter:column.filter.name:column.filter.options:row.addThisToo }}