Meu objective é aplicar um filtro de formatação definido como uma propriedade do object em loop.
Tomando essa matriz de objects:
[ { "value": "test value with null formatter", "formatter": null, }, { "value": "uppercase text", "formatter": "uppercase", }, { "value": "2014-01-01", "formatter": "date", } ]
O código do modelo que estou tentando escrever é o seguinte:
{{ row.value | row.formatter }}
E eu estou esperando ver esse resultado :
test value with null formatter UPPERCASE TEXT Jan 1, 2014
Mas talvez obviusly este código lança um erro:
Unknown provider: row.formatterFilterProvider <- row.formatterFilter
Não consigo imaginar como analisar o parâmetro “formatter” dentro do {{}}; Alguém pode me ajudar?
Veja o plunkr http://plnkr.co/edit/YnCR123dRQRqm3owQLcs?p=preview
O |
é uma construção angular que encontra um filtro definido com esse nome e aplica-o ao valor à esquerda. O que eu acho que você precisa fazer é criar um filtro que use um nome de filtro como argumento e, em seguida, chame o filtro apropriado (violino) (adaptado do código do M59):
HTML:
{{ row.value | picker:row.formatter }}
Javascript:
app.filter('picker', function($filter) { return function(value, filterName) { return $filter(filterName)(value); }; });
Graças ao comentário do @ karlgold, aqui está uma versão que suporta argumentos. O primeiro exemplo usa o filtro add
diretamente para adicionar números a um número existente e o segundo usa o filtro useFilter
para selecionar o filtro add
por string e passar argumentos para ele (fiddle) :
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); }; });
Eu gosto do conceito por trás dessas respostas, mas não acho que elas fornecem a solução mais flexível possível.
O que eu realmente queria fazer e tenho certeza de que alguns leitores sentirão o mesmo, é poder passar dinamicamente uma expressão de filtro, que então avaliaria e retornaria o resultado apropriado.
Assim, um único filtro personalizado poderia processar todos os itens a seguir:
{{ammount | picker:'currency:"$":0'}}
{{date | picker:'date:"yyyy-MM-dd HH:mm:ss Z"'}}
{{name | picker:'salutation:"Hello"'}}
{{name | picker:'salutation:"Hello"'}}
// Aplicar outro filtro personalizado
Eu criei o seguinte código, que utiliza o serviço $interpolate
em meu filtro personalizado. Veja o jsfiddle :
Javascript
myApp.filter('picker', function($interpolate ){ return function(item,name){ var result = $interpolate('{{value | ' + arguments[1] + '}}'); return result({value:arguments[0]}); }; });
Uma maneira de fazer isso funcionar é usar uma function para a binding e fazer a filtragem dentro dessa function. Essa pode não ser a melhor abordagem: demonstração ao vivo (clique).
{{ foo(row.value, row.filter) }}
JavaScript:
$scope.list = [ {"value": "uppercase text", "filter": "uppercase"} ]; $scope.foo = function(value, filter) { return $filter(filter)(value); };
Eu tive uma necessidade um pouco diferente e modifiquei a resposta acima um pouco (a solução $interpolate
atinge o mesmo objective, mas ainda é 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 }}
Dados:
{ label:"Column head", description:"The label used for a column", filter:"percentage:2:true", fakeData:-4.769796600014472 }
( percentage
é um filtro personalizado que cria um number
)
Crédito neste post para Jason Goemaat.
Aqui está como eu usei.
$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 ); }; }]);
Eu melhorei a resposta do @Jason Goemaat adicionando uma verificação se o filtro existe, e se não retornar o primeiro argumento por padrão:
.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]; }; });
A versão mais nova do ng-table permite a criação de tabelas dinâmicas (ng-dynamic-table) com base em uma configuração de coluna. Formatar um campo de data é tão fácil quanto adicionar o formato ao valor do seu campo na matriz de colunas.
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 }) }}
Acabei fazendo algo um pouco mais grosseiro, mas envolvendo menos:
HTML:
Use o operador ternário para verificar se existe um filtro definido para a linha:
ng-bind="::data {{row.filter ? '|' + row.filter : ''}}"
JS:
Na matriz de dados em JavaScript, adicione o filtro:
, { data: 10, rowName: "Price", months: [], tooltip: "Price in DKK", filter: "currency:undefined:0" }, {
Isso é o que eu uso (versão Angular 1.3.0-beta.8 acidental-haiku).
Este filtro permite que você use filtros com ou sem opções de filtro.
applyFilter irá verificar se o filtro existe em Angular, se o filtro não existir, então uma mensagem de erro com o nome do filtro estará no console do navegador assim …
O seguinte filtro não existe: greenBananas
Ao usar ng-repeat , alguns dos valores serão indefinidos. O applyFilter lidará com esses problemas com uma falha 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; } }]);
Então você usa o filtro que quiser, que pode ou não ter opções.
// Where, item => { name: "Jello", filter: {name: "capitalize", options: null }}; {{ item.name | applyFilter:item.filter.name:item.filter.options }}
Ou você poderia usar com estruturas de dados separadas ao criar uma tabela.
// Where row => { color: "blue" }; // column => { name: "color", filter: { name: "capitalize", options: "whatever filter accepts"}}; {{ row[column.name] | applyFilter:column.filter.name:column.filter.options }}
Se você achar que precisa passar em valores mais específicos, você pode adicionar mais 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);
Em seguida, no seu HTML, talvez o seu filtro também exija uma chave do object de linha
// 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 }}