Angular filter with ng-repeat giving strange error

Asked

Viewed 351 times

0

Folks I’m having trouble using a filter in conjunction with ng-repeat. I have a json of events where I want that when selecting an event type in select, the filter returns a new json with only the events that have the event type chosen, this is my code

CONTROLLER

            $scope.filtro = "";
            $scope.eventos = [
            {
                data: "2016-05-09",
                eventos: [1, 5, 3, 7]
            },
            {
                data: "2016-05-08",
                eventos: [2, 0]
            },
            {
                data: "2016-05-07",
                eventos: [0, 3, 6]
            },
            {
                data: "2016-04-03",
                eventos: [1, 6, 7, 8]
            },
            {
                data: "2016-04-02",
                eventos: [7]
            },
            {
                data: "2015-01-01",
                eventos: [7, 3]
            }
        ];

HTML

    <div ng-repeat="(key,evento) in (eventos|filtraEvento:filtro)">
        <div><b style="color:red">{{key}}º) - </b>{{evento.data}}</div>
        <div>
            <span ng-repeat="e in evento.eventos">[{{e}}]</span>
        </div>
    </div>
    <select ng-model="filtro">
        <option value="0">0</option>
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
        <option value="4">4</option>
        <option value="5">5</option>
        <option value="6">6</option>
        <option value="7">7</option>
        <option value="8">8</option>
    </select>

FILTER

.filter('filtraEvento', ['Util', function (Util) {
    return function (eventos, tipoEvento) {
        var eventosFiltrado = [];
        if (!Util.isNull(tipoEvento)) {
            for (var i = 0; i < eventos.length; i++) {
                var evento = [];
                for (var j = 0; j < eventos[i].eventos.length; j++) {
                    if (eventos[i].eventos[j] == tipoEvento) {
                        evento.push(eventos[i].eventos[j]);
                    }
                }
                if (evento.length > 0) {
                    eventosFiltrado.push({
                        data: eventos[i].data,
                        eventos: evento
                    });
                }

            }
        } else {
            eventosFiltrado = eventos;
        }
        return eventosFiltrado;
    }
}]);

without filtering the system displays normal, but if I choose some filter, besides giving the error:

  "Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!"

the system has many times doubled the result: Ex: If I choose the filter "2" the displayed result would be:

1º)2016-05-08
1º)2016-05-08
1º)2016-05-08
1º)2016-05-08
1º)2016-05-08
.
.
.
seguido do json original

Thanks for any help, sorry if I did anything out of the standard of the site, I’m new here

2 answers

0


Hello from what I understand you want to filter which dates have the selected number.

I put a field identifier in JSON so that you can use the angle filter itself see below how JSON turned out.

          $scope.eventos = [
        {
            data: "2016-05-09",
            eventos: [
              {numero: 1}, 
              {numero: 5}, 
              {numero: 3}, 
              {numero: 7}
              ]
        },
        {
            data: "2016-05-08",
            eventos: [
              {numero:2},
              {numero:0}
              ]
        },
        {
            data: "2016-05-07",
            eventos: [
              {numero:0},
              {numero:3},
              {numero:6}
              ]
        },
        {
            data: "2016-04-03",
            eventos: [
              {numero:1}, 
              {numero:6}, 
              {numero:7}, 
              {numero:8}
              ]
        },
        {
            data: "2016-04-02",
            eventos: [{numero:7}]
        },
        {
            data: "2015-01-01",
            eventos: [
                {numero:7}, 
                {numero:3}
              ]
        }
    ];

Then I put a filter parameter I named as filterTxn

   <div ng-repeat="evento in eventos  | filter: filterTxn">

And I put this parameter in your ng-model as the name of the field that Voce wants to filter in JSON in case and node number field events so it is filterTxn.eventos.numero.

   <select ng-model="filterTxn.eventos.numero">

When selecting select it filters and displays only the data containing the selected number.

An OBS like the Event Node contains an Array of numbers it brings the entire Array.

I hope I’ve helped publish in Plunker this test if you want to see.

https://plnkr.co/edit/MKGpSxWUvcTOz42kEt1X?p=preview

  • thanks ! worked perfectly, I appreciate the kindness and dedication in helping me

0

If you care about performance, DON’T USE PIPE FILTER

(eventos | filtraEvento:filtro) //Não use o filtro assim ' | filtro'

Each $Digest interaction, regardless of whether it originated from the filter, an ng-click, or any other type of trigger, will run your filter 2 times for $Digest. That is, roughly speaking, any other interaction you have in your view will run this filter, even if it has nothing to do with the filter itself.

How to solve? Do this in the controller and update only the $Scope value, so you will run the filter only 1 time and when it is actually used.

Like? (And now I answer your question too). It’s important to note that you don’t need to change your JSON structure to make it work, okay? Another difference is that you can simplify your code using:

angular.forEach(colecao, function(objeto, index) {
    //Loop aqui
})

This replaces the for (). Now below is an example of how to use it in your controller:

var eventos = [
    { 
        data: "2016-05-09",
        eventos: [1, 5, 3, 7]
    },
    [...etc...]
];

$scope.eventos = eventos;

/* Função de Filtro */
$scope.rodaFiltro = function(filtro) {

    if (filtro) { //Se algum filtro foi selecionado, aplicamos a filtragem
        var filtrados = [];

        angular.forEach(eventos, function(obj){ //Loop na coleção
            angular.forEach(obj.eventos, function (item) { //Loop no tipo de evento
                if(item == filtro) { //Verifica se o evento é igual a um dos eventos cadastrados na data
                    filtrados.push(obj); //Se sim, coloca ele na array de filtrados
                }
            })
        })

        $scope.eventos = filtrados; //Atualiza a lista

    } else { //Se nenhum filtro foi selecionado, voltamos a lista original
        $scope.eventos = eventos;
    }
}

See an example working: https://plnkr.co/edit/ILoCL2?p=preview

Browser other questions tagged

You are not signed in. Login or sign up in order to post.