web-dev-qa-db-fra.com

appliquer le filtre de formatage dynamiquement dans un ng-repeat

Mon objectif est d'appliquer un filtre de formatage défini en tant que propriété de l'objet en boucle.

Prenant ce tableau d'objets:

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

Le code de modèle que j'essaie d'écrire est le suivant:

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

Et je suis espérant voir ce résultat:

test value with null formatter
UPPERCASE TEXT
Jan 1, 2014

Mais peut-être que ce code génère apparemment une erreur:

Unknown provider: row.formatterFilterProvider <- row.formatterFilter

Je ne peux pas immaginer comment analyser le paramètre "formateur" à l'intérieur du {{}}; Quelqu'un peut-il m'aider?

Voir le plunkr http://plnkr.co/edit/YnCR123dRQRqm3owQLcs?p=preview

30
IcedBlind

| est une construction angulaire qui trouve un filtre défini avec ce nom et l'applique à la valeur de gauche. Ce que je pense que vous devez faire est de créer un filtre qui prend comme argument un filtre nom, puis appelle le filtre approprié (violon) (adapté du code de 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);
  };
});

Grâce au commentaire de @ karlgold, voici une version qui supporte les arguments. Le premier exemple utilise directement le filtre add pour ajouter des nombres à un numéro existant et le second utilise le filtre useFilter pour sélectionner le filtre add par chaîne et lui transmettre des arguments (violon) :

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);
    };
});
57
Jason Goemaat

J'aime le concept derrière ces réponses, mais je ne pense pas qu'elles fournissent la solution la plus flexible possible. 

Ce que je voulais vraiment faire et je suis sûr que certains lecteurs ressentiront la même chose est de pouvoir passer dynamiquement une expression de filtre, qui évaluerait et renverrait le résultat approprié. 

Ainsi, un seul filtre personnalisé serait en mesure de traiter tous les éléments suivants:

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

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

{{name | picker:'salutation:"Hello"'}}/ Appliquer un autre filtre personnalisé

Je suis arrivé avec le morceau de code suivant, qui utilise le service $interpolate dans mon filtre personnalisé. Voir le jsfiddle :

_/Javascript

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

Une façon de le faire fonctionner consiste à utiliser une fonction pour la liaison et à effectuer le filtrage au sein de cette fonction. Ce n'est peut-être pas la meilleure approche: Démonstration en direct (clic).

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

J'ai fini par faire quelque chose d'un peu plus brut, mais moins complexe:

HTML:

Utilisez l'opérateur ternaire pour vérifier si un filtre est défini pour la ligne:

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

JS:

Dans le tableau de données en Javascript, ajoutez le filtre:

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

C'est ce que j'utilise (version angulaire 1.3.0-beta.8 accidental-haiku).

Ce filtre vous permet d'utiliser des filtres avec ou sans options de filtre.

applyFilter vérifiera si le filtre existe dans Angular. Si le filtre n'existe pas, un message d'erreur portant le nom du filtre apparaîtra dans la console du navigateur, comme suit ...

Le filtre suivant n'existe pas: greenBananas

Lorsque vous utilisez ng-repeat, certaines valeurs ne sont pas définies. applyFilter gérera ces problèmes avec une défaillance logicielle.

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

Ensuite, vous utilisez le filtre de votre choix, avec ou sans 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>

Ou vous pouvez utiliser des structures de données distinctes lors de la construction d'une 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>

Si vous estimez avoir besoin de transmettre des valeurs plus spécifiques, vous pouvez ajouter d'autres arguments comme celui-ci ...

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

Ensuite, dans votre code HTML, votre filtre nécessite peut-être aussi une clé de la row object

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

La nouvelle version de ng-table permet de créer une table dynamique (ng-dynamic-table) basée sur une configuration de colonne. Le formatage d'un champ de date est aussi simple que l'ajout du format à la valeur de votre champ dans votre tableau de colonnes.

Donné

{
    "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>
0
Steve Carlson

Crédit à ce poste à Jason Goemaat.

Voici comment je l'ai utilisé.

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

J'avais un besoin légèrement différent et j'ai donc modifié un peu la réponse ci-dessus (la solution $interpolate a le même objectif mais reste limitée):

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>

Les données:

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

(percentage est un filtre personnalisé qui repose sur number)

0
bbrown

J'ai amélioré un peu la réponse de @Jason Goemaat en ajoutant une vérification si le filtre existe, et si ce n'est pas le cas, je retourne le premier argument par défaut:

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