Función de filtro personalizado AngularJS

91

Dentro de mi controlador, me gustaría filtrar una matriz de objetos. Cada uno de estos objetos es un mapa que puede contener cadenas y listas

Intenté usar el $filter('filter')(array, function)formato pero no sé cómo acceder a los elementos individuales de la matriz dentro de mi función. Aquí hay un fragmento para mostrar lo que quiero.

$filter('filter')(array, function() {
  return criteriaMatch(item, criteria);
});

Y luego, en el criteriaMatch(), verificaré si cada una de las propiedades individuales coincide

var criteriaMatch = function(item, criteria) {
  // go thro each individual property in the item and criteria
  // and check if they are equal
}

Tengo que hacer todo esto en el controlador y compilar una lista de listas y configurarlas en el alcance. Así que necesito acceder $filter('filter')solo de esta manera. Todos los ejemplos que encontré en la red hasta ahora tienen búsquedas de criterios estáticos dentro de la función, no pasan un objeto de criterios y prueban cada elemento de la matriz.

usuario2368436
fuente
3
¿Por qué necesitas un filtro? Por lo general, los filtros se utilizan a partir de plantillas. ¿No puede tener una función simple en su controlador si solo lo está usando desde allí?
Ketan
en lugar de pasar manualmente por cada elemento de la matriz, pensé que podríamos usar la funcionalidad $ filter ('filter') de angular (que se encargará de iterar a través de cada elemento si solo especificamos la función de predicado)
user2368436

Respuestas:

173

Puede usarlo así: http://plnkr.co/edit/vtNjEgmpItqxX5fdwtPi?p=preview

Como encontró, filteracepta la función de predicado que acepta elemento por elemento de la matriz. Entonces, solo tiene que crear una función de predicado basada en lo dado criteria.

En este ejemplo, criteriaMatches una función que devuelve una función de predicado que coincide con la dada criteria.

modelo:

<div ng-repeat="item in items | filter:criteriaMatch(criteria)">
  {{ item }}
</div>

alcance:

$scope.criteriaMatch = function( criteria ) {
  return function( item ) {
    return item.name === criteria.name;
  };
};
Tosh
fuente
No voy a utilizar esta función criteriaMatch del html ... ¿cómo la llamaré desde dentro del controlador? ¿Es correcto? $ filter ('filter') (matriz, función () {return criteriaMatch (elemento, criterios);});
user2368436
6
Si no lo está utilizando en su plantilla, definir el filtro no le da ninguna ventaja. Simplemente puede definir una función javascript simple, ya que allí es aún más corta. Puede usar el filtermétodo nativo en el objeto Array:array.filter(function(item){return item.name === criteria.name;})
Tosh
Tengo una función de javascript. solo quería asegurarme de que angular no tuviera una forma más fácil de hacerlo ... aceptaré su respuesta. Gracias.
user2368436
2

Aquí hay un ejemplo de cómo lo usaría filterdentro de su JavaScript AngularJS (en lugar de en un elemento HTML).

En este ejemplo, tenemos una matriz de registros de países, cada uno con un nombre y un código ISO de 3 caracteres.

Queremos escribir una función que busque en esta lista un registro que coincida con un código específico de 3 caracteres.

Así es como lo haríamos sin usar filter:

$scope.FindCountryByCode = function (CountryCode) {
    //  Search through an array of Country records for one containing a particular 3-character country-code.
    //  Returns either a record, or NULL, if the country couldn't be found.
    for (var i = 0; i < $scope.CountryList.length; i++) {
        if ($scope.CountryList[i].IsoAlpha3 == CountryCode) {
            return $scope.CountryList[i];
        };
    };
    return null;
};

Sí, no hay nada de malo en eso.

Pero así es como se vería la misma función, usando filter:

$scope.FindCountryByCode = function (CountryCode) {
    //  Search through an array of Country records for one containing a particular 3-character country-code.
    //  Returns either a record, or NULL, if the country couldn't be found.

    var matches = $scope.CountryList.filter(function (el) { return el.IsoAlpha3 == CountryCode; })

    //  If 'filter' didn't find any matching records, its result will be an array of 0 records.
    if (matches.length == 0)
        return null;

    //  Otherwise, it should've found just one matching record
    return matches[0];
};

Mucho más ordenado.

Recuerde que filterdevuelve una matriz como resultado (una lista de registros coincidentes), por lo que en este ejemplo, queremos devolver 1 registro o NULL.

Espero que esto ayude.

Mike Gledhill
fuente
0

Además, si desea usar el filtro en su controlador de la misma manera que lo hace aquí:

<div ng-repeat="item in items | filter:criteriaMatch(criteria)">
  {{ item }}
</div>

Podrías hacer algo como:

var filteredItems =  $scope.$eval('items | filter:filter:criteriaMatch(criteria)');
cafesanu
fuente
6
Alternativamente,var filteredItems = $filter('criteriaMatch')(items, criteria);
321zeno