Como aplicar filtros ao * ngFor?


278

Aparentemente, o Angular 2 usará pipes em vez de filtros, como no Angular1 em conjunto com ng-for para filtrar os resultados, embora a implementação ainda pareça vaga, sem documentação clara.

Ou seja, o que estou tentando alcançar pode ser visto da seguinte perspectiva

<div *ng-for="#item of itemsList" *ng-if="conditon(item)"></div>

Como implementar isso usando tubos?


8
Observe que uma alteração de quebra é introduzida na versão beta 17 para ngFor em relação ao símbolo de hash. A maneira correta é:<div *ngFor="let item of itemsList" *ngIf="conditon(item)" ...
Memet Olsen


11
@MemetOlsen comenta de Gunter abaixo: " *ngFore *ngIfo mesmo elemento não é suportado. Você precisa mudar para a forma explícita de um deles"
The Red Pea

1
Mesmo que seja o que o OP solicita, é recomendável NÃO USAR O TUBO para filtrar ou fazer pedidos no Angular2 +. Prefere tendo uma propriedade de classe com os valores filtrados: angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe
ylerjen

Respostas:


395

Basicamente, você escreve um pipe que pode ser usado na *ngFordiretiva.

No seu componente:

filterargs = {title: 'hello'};
items = [{title: 'hello world'}, {title: 'hello kitty'}, {title: 'foo bar'}];

No seu modelo, você pode passar uma string, número ou objeto para o seu pipe para usar para filtrar:

<li *ngFor="let item of items | myfilter:filterargs">

No seu pipe:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
    name: 'myfilter',
    pure: false
})
export class MyFilterPipe implements PipeTransform {
    transform(items: any[], filter: Object): any {
        if (!items || !filter) {
            return items;
        }
        // filter items array, items which match and return true will be
        // kept, false will be filtered out
        return items.filter(item => item.title.indexOf(filter.title) !== -1);
    }
}

Lembre-se de registrar seu cachimbo app.module.ts; você não precisa mais registrar os tubos no seu@Component

import { MyFilterPipe } from './shared/pipes/my-filter.pipe';

@NgModule({
    imports: [
        ..
    ],
    declarations: [
        MyFilterPipe,
    ],
    providers: [
        ..
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

Aqui está um Plunker que demonstra o uso de um tubo de filtro personalizado e o tubo de fatia incorporado para limitar os resultados.

Observe (como vários comentaristas apontaram) que há uma razão pela qual não há tubos de filtro embutidos no Angular.


6
Thanx, isso funciona como pretendido, mas às vezes é melhor verificar se a matriz de itens está definida e não nula, porque o Ng2 pode tentar aplicar o filtro enquanto os "itens" ainda não estão definidos.
timmz

1
Além disso, eu precisava adicionar a classe de filtro à declaração @Component. Assim: @Component ({... tubos: [MyFilterPipe]
Stephen

1
Eu acho que ele também precisa dessa linha ìf (! Itens) retorna itens; `caso a matriz esteja vazia.
Boštjan Pišler

2
Angular diz através de um tubo tem de executar questões, por isso recomenda que seja filtrando o componente
Sebastián Rojas

3
Gostaria de sugerir quebra de *ngForparâmetros entre parênteses, apenas para evitar qualquer confusão e torná-la "à prova de alterações":<li *ngFor="let item of (items | myfilter:filterargs)">
Tomas

104

Muitos de vocês têm ótimas abordagens, mas o objetivo aqui é ser genérico e definir um canal de matriz extremamente reutilizável em todos os casos em relação a * ngFor.

callback.pipe.ts (não esqueça de adicionar isso ao array de declaração do seu módulo)

import { PipeTransform, Pipe } from '@angular/core';

@Pipe({
    name: 'callback',
    pure: false
})
export class CallbackPipe implements PipeTransform {
    transform(items: any[], callback: (item: any) => boolean): any {
        if (!items || !callback) {
            return items;
        }
        return items.filter(item => callback(item));
    }
}

Então, em seu componente, você precisa implementar um método com a seguinte assinatura (item: any) => booleano , no meu caso, por exemplo, eu chamei de filterUser, que filtra a idade dos usuários com mais de 18 anos.

Seu componente

@Component({
  ....
})
export class UsersComponent {
  filterUser(user: IUser) {
    return !user.age >= 18
  }
}

E por último, mas não menos importante, seu código html ficará assim:

O seu HTML

<li *ngFor="let user of users | callback: filterUser">{{user.name}}</li>

Como você pode ver, esse Pipe é bastante genérico em toda a matriz, como itens que precisam ser filtrados por meio de um retorno de chamada. No mycase, achei muito útil para * ngPara cenários semelhantes.

Espero que isto ajude!!!

codematrix


4
Percebo que na função filterUser () - ou na minha função equivalente a isso - você não pode usar "this" para acessar a instância atual do componente como em todas as outras funções da classe component. Preciso acessar o objeto componente para verificar se o item filtrado está em uma coleção.
Paul

1
@ Paul, hmm ... isso é impossível. O seu método é privado? Isso não importa, pois os particulares são apenas construções de compilação e não são impostos em tempo de execução. No meu exemplo, usei IUser. Isso pressupõe que os itens da coleção que estão sendo iterados sejam mapeados para ela. Você pode tentar qualquer um para ver se funciona. Além disso, verifique se o nome está digitado corretamente, maiúsculas e minúsculas.
Código5

1
eu não posso acessar variável componente utilizando este método
suulisin

10
Para evitar o problema de thisser indefinido, você pode escrever seu método em seu componente como filterUser = (user: IUser) =>, em vez defilteruser(user: IUser)
Tom

2
@ Paul Eu sei que é tarde demais para ajudá-lo, mas pode ajudar outras pessoas. A razão pela qual você estava perdendo thisno método de componente é porque o método estava sendo usado como retorno de chamada e um novo thiscontexto foi aplicado. Você encontrou um problema comum no javascript orientado a objetos, mas há uma solução antiga e fácil: você vincula métodos a serem usados ​​como retornos de chamada na classe original. No seu construtor, adicione o seguinte código: this.myCallbackFunc = this.myCallbackFunc.bind(this); É isso. Você nunca perderá thisnovamente.
Randolpho

36

Maneira simplificada (Usado apenas em matrizes pequenas devido a problemas de desempenho. Em matrizes grandes, é necessário fazer o filtro manualmente via código):

Consulte: https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe

@Pipe({
    name: 'filter'
})
@Injectable()
export class FilterPipe implements PipeTransform {
    transform(items: any[], field : string, value : string): any[] {  
      if (!items) return [];
      if (!value || value.length == 0) return items;
      return items.filter(it => 
      it[field].toLowerCase().indexOf(value.toLowerCase()) !=-1);
    }
}

Uso:

<li *ngFor="let it of its | filter : 'name' : 'value or variable'">{{it}}</li>

Se você usar uma variável como segundo argumento, não use aspas.


3
Talvez adicione o seguinte para mostrar como combiná-lo com ReqExp: return items.filter (item => {retorne novo RegExp (valor, "i"). Test (item [campo])});
Johannes

8
Segundo a equipe Angular, isso é considerado uma má prática.

@torazaburo você pode consultar a opinião deles ou explicar o porquê? Obrigado
Zymotik


2
De acordo com a equipe Angular, esse é um código ruim, porque é lento e não é minificado bem. A equipe não deseja ver sites lentos devido ao código, para que não o incorporem ao Angular dessa vez. angular.io/docs/ts/latest/guide/…
Zymotik

29

Isso é o que eu implementei sem usar o pipe.

component.html

<div *ngFor="let item of filter(itemsList)">

component.ts

@Component({
....
})
export class YourComponent {
  filter(itemList: yourItemType[]): yourItemType[] {
    let result: yourItemType[] = [];
    //your filter logic here
    ...
    ...
    return result;
  }
}

16
Eu acho que isso seria computacionalmente intensivo porque o Angular executará o filtro toda vez que executar a detecção de alterações. Não será dimensionado bem para matrizes grandes. Um limpador, embora mais complexo de código, a solução seria fazer itemListum observável e usar o filtro assíncrona: let item of itemsList | async. Quando ocorrer uma alteração, faça o observável emitir a nova lista. Dessa forma, o código de filtragem é executado apenas quando necessário.
precisa saber é o seguinte

1
Esta resposta deve ter uma pontuação negativa. É ruim, use um cachimbo.
Cétia 14/02


11

Você também pode usar o seguinte:

<template ngFor let-item [ngForOf]="itemsList">
    <div *ng-if="conditon(item)"></div>
</template>

Isso só mostrará a div se seus itens corresponderem à condição

Consulte a documentação angular para obter mais informações Se você também precisar do índice, use o seguinte:

<template ngFor let-item [ngForOf]="itemsList" let-i="index">
    <div *ng-if="conditon(item, i)"></div>
</template>

1
Isso não inserirá o modelo para cada item da lista, e não apenas a lista filtrada? Isso pode ser um impacto no desempenho.
Azeroth2b

8

tubos no Angular2 são semelhantes aos tubos na linha de comando. A saída de cada valor anterior é inserida no filtro após o tubo, o que facilita a cadeia de filtros, assim:

<template *ngFor="#item of itemsList">
    <div *ngIf="conditon(item)">{item | filter1 | filter2}</div>
</template>

Desculpe se isso foi enganoso, meu ponto aqui é a variável itemfrom *ng-for="#item of itemsList"deve ser usada para filtrar os resultados como tal *ng-if="conditon(item)". O que não funciona neste exemplo.
Khaled

você poderia transformar um filtro em condição e fazer o mesmo com {{item | condição}} a condição retornaria apenas itemse a condição for atendida e nenhum valor se não for.
Ben Glasser

@BenGlasser Pensei que os canos fossem aplicados da direita para a esquerda. Portanto, isso aplicaria primeiro o filtro2, depois o filtro1.
Evan Plaice

12
*ngFore *ngIfno mesmo elemento não são suportados. Você precisa mudar para a forma explícita para um deles<template ngFor ...>
Günter Zöchbauer

1
@ GünterZöchbauer Levei um ano, mas eu atualizei a sintaxe para refletir as alterações sugeridas
Ben Glasser

5

Para esse requisito, implementei e publico um componente genérico . Vejo

https://www.npmjs.com/package/w-ng5

Para usar esses componentes, antes, instale este pacote com o npm:

npm install w-ng5 --save

Depois, importe o módulo no app.module

...
import { PipesModule } from 'w-ng5';

Na próxima etapa, adicione a seção declarar do app.module:

imports: [
  PipesModule,
  ...
]

Uso da amostra

Filtrando sequência simples

<input type="text"  [(ngModel)]="filtroString">
<ul>
  <li *ngFor="let s of getStrings() | filter:filtroString">
    {{s}}
  </li>
</ul>

Filtrar cadeia complexa - campo 'Valor' no nível 2

<input type="text"  [(ngModel)]="search">
<ul>
  <li *ngFor="let s of getComplexTypesExtends() | filter:[{field:'n1.n2.valor2', value: search}]">
    {{s.nome}} - {{s.idade}} - {{s.n1.valor1}} - {{s.n1.n2.valor2}}
  </li>
</ul>

Filtragem de cadeia complexa - campo do meio - 'Valor' no nível 1

<input type="text"  [(ngModel)]="search3">
<ul>
  <li *ngFor="let s of getComplexTypesExtends() | filter:[{field:'n1.valor1', value: search3}]">
    {{s.nome}} - {{s.idade}} - {{s.n1.valor1}} - {{s.n1.n2.valor2}}
  </li>
</ul>

Filtragem de matriz complexa simples - campo 'Nome' nível 0

<input type="text"  [(ngModel)]="search2">
<ul>
  <li *ngFor="let s of getComplexTypesExtends() | filter:[{field:'nome', value: search2}]">
    {{s.nome}} - {{s.idade}} - {{s.n1.valor1}} - {{s.n1.n2.valor2}}
  </li>
</ul>

Filtrando em campos de árvore - campo 'Valor' no nível 2 ou 'Valor' no nível 1 ou 'Nome' no nível 0

<input type="text"  [(ngModel)]="search5">
<ul>
  <li *ngFor="let s of getComplexTypesExtends() | filter:[{field:'n1.n2.valor2', value: search5}, {field:'n1.valor1', value: search5}, {field:'nome', value: search5}]">
    {{s.nome}} - {{s.idade}} - {{s.n1.valor1}} - {{s.n1.n2.valor2}}
  </li>
</ul>

Filtrando campo inexistente - 'Valor' no nível inexistente 3

<input type="text"  [(ngModel)]="search4">
<ul>
  <li *ngFor="let s of getComplexTypesExtends() | filter:[{field:'n1.n2.n3.valor3', value: search4}]">
    {{s.nome}} - {{s.idade}} - {{s.n1.valor1}} - {{s.n1.n2.valor2}}
  </li>
</ul>

Este componente trabalha com nível de atributo infinito ...


Olá, estou aqui e segui todas as etapas e, neste caso, estou usando isso *ngFor="let inovice of invoices | filter:searchInvoice"e ele está pesquisando na minha lista, mas mostra uma lista em branco, você sabe por quê?
jecorrales

1
Olá, diga-me qual é a estrutura e o tipo de objetos que sua lista de faturas contém. O modo como você o usa deve ser aplicado apenas se a sua lista de faturas for do tipo string. Se você deseja pesquisar por número da fatura (invoice.number), use o seguinte: * ngFor = "deixe inovação de faturas | filtrar: {campo: número, valor: searchInvoice}" . Se você deseja filtrar por duas colunas, por exemplo, invoice.customer.name, use: * ngFor = "deixe inovação de faturas | filtrar: [campo: número, valor: searchInvoice}, {campo: customer.name, valor: searchInvoice}] .
Wedson Quintanilha da Silva

4

Uma solução simples que funciona com o Angular 6 para filtrar um ngFor, é a seguinte:

<span *ngFor="item of itemsList"  >
  <div *ngIf="yourCondition(item)">
    
    your code
    
  </div>
</span

Os períodos são úteis porque não representam nada inerentemente.


1
melhor que <span> é usar <ng-container>, pois ele não adiciona nenhuma marcação desnecessária que, além do ruído html, pode afetar seu CSS.
Trevor de Koekkoek

4

Sei que é uma pergunta antiga, no entanto, pensei que poderia ser útil oferecer outra solução.

equivalente a AngularJS deste

<div *ng-for="#item of itemsList" *ng-if="conditon(item)"></div>

no Angular 2+, você não pode usar * ngFor e * ngIf em um mesmo elemento; portanto, será o seguinte:

<div *ngFor="let item of itemsList">
     <div *ngIf="conditon(item)">
     </div>
</div>

e se você não puder usar como contêiner interno, use ng-container. ng-container é útil quando você deseja anexar condicionalmente um grupo de elementos (por exemplo, usando * ngIf = "foo") em seu aplicativo, mas não deseja agrupá-los com outro elemento.


4

Eu criei um plunker com base nas respostas aqui e em outros lugares.

Além disso eu tinha que adicionar um @Input, @ViewChilde ElementRefdo <input>e criar e subscribe()para um observável dele.

Filtro de pesquisa Angular2: PLUNKR (UPDATE: plunker não funciona mais)


3

Pipe seria a melhor abordagem. mas abaixo de um também funcionaria.

<div *ng-for="#item of itemsList">
  <ng-container *ng-if="conditon(item)">
    // my code
  </ng-container>
</div>

isso pode quebrar certas coisas. por exemplo dentro de uma esteira em forma de campo
pcnate

2

Este é o meu código:

import {Pipe, PipeTransform, Injectable} from '@angular/core';

@Pipe({
    name: 'filter'
})
@Injectable()
export class FilterPipe implements PipeTransform {
    transform(items: any[], field : string, value): any[] {
      if (!items) return [];
      if (!value || value.length === 0) return items;
      return items.filter(it =>
      it[field] === value);
    }
}

Amostra:

LIST = [{id:1,name:'abc'},{id:2,name:'cba'}];
FilterValue = 1;

<span *ngFor="let listItem of LIST | filter : 'id' : FilterValue">
                              {{listItem .name}}
                          </span>

1

Outra abordagem que eu gosto de usar para filtros específicos de aplicativos é usar uma propriedade somente leitura personalizada em seu componente, que permite encapsular a lógica de filtragem de maneira mais limpa do que usar um pipe personalizado (IMHO).

Por exemplo, se eu desejar vincular albumListe filtrar searchText:

searchText: "";
albumList: Album[] = [];

get filteredAlbumList() {
    if (this.config.searchText && this.config.searchText.length > 1) {
      var lsearchText = this.config.searchText.toLowerCase();
      return this.albumList.filter((a) =>
        a.Title.toLowerCase().includes(lsearchText) ||
        a.Artist.ArtistName.toLowerCase().includes(lsearchText)
      );
    }
    return this.albumList;
}

Para vincular o HTML, você pode vincular à propriedade somente leitura:

<a class="list-group-item"
       *ngFor="let album of filteredAlbumList">
</a>

Acho que para filtros especializados, específicos da aplicação, isso funciona melhor do que um pipe, pois mantém a lógica relacionada ao filtro com o componente.

Os tubos funcionam melhor para filtros reutilizáveis ​​globalmente.


1
Esse método não acionará verificações sujas contínuas em vez de usar uma abordagem valueChanged?
Léon Pelletier

1

Criei o seguinte canal para obter os itens desejados de uma lista.

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'filter'
})
export class FilterPipe implements PipeTransform {

  transform(items: any[], filter: string): any {
    if(!items || !filter) {
      return items;
    }
    // To search values only of "name" variable of your object(item)
    //return items.filter(item => item.name.toLowerCase().indexOf(filter.toLowerCase()) !== -1);

    // To search in values of every variable of your object(item)
    return items.filter(item => JSON.stringify(item).toLowerCase().indexOf(filter.toLowerCase()) !== -1);
  }

}

Conversão em minúsculas é apenas para corresponder de maneira insensível a maiúsculas. Você pode usá-lo em sua visualização da seguinte maneira: -

<div>
  <input type="text" placeholder="Search reward" [(ngModel)]="searchTerm">
</div>
<div>
  <ul>
    <li *ngFor="let reward of rewardList | filter:searchTerm">
      <div>
        <img [src]="reward.imageUrl"/>
        <p>{{reward.name}}</p>
      </div>
    </li>
  </ul>
</div>

1

Idealmente, você deve criar um tubo angualr 2 para isso. Mas você pode fazer esse truque.

<ng-container *ngFor="item in itemsList">
    <div*ngIf="conditon(item)">{{item}}</div>
</ng-container>

1

Com base na solução de pipe de retorno de chamada muito elegante proposta acima, é possível generalizá-la um pouco mais, permitindo que parâmetros adicionais de filtro sejam transmitidos. Temos então:

callback.pipe.ts

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'callback',
  pure: false
})
export class CallbackPipe implements PipeTransform {
  transform(items: any[], callback: (item: any, callbackArgs?: any[]) => boolean, callbackArgs?: any[]): any {
    if (!items || !callback) {
      return items;
    }
    return items.filter(item => callback(item, callbackArgs));
  }
}

componente

filterSomething(something: Something, filterArgs: any[]) {
  const firstArg = filterArgs[0];
  const secondArg = filterArgs[1];
  ...
  return <some condition based on something, firstArg, secondArg, etc.>;
}

html

<li *ngFor="let s of somethings | callback : filterSomething : [<whatWillBecomeFirstArg>, <whatWillBecomeSecondArg>, ...]">
  {{s.aProperty}}
</li>

0

Aqui está um exemplo que eu criei há algum tempo, e escrevi em um blog, que inclui um esforço de trabalho. Ele fornece um tubo de filtro que pode filtrar qualquer lista de objetos. Basicamente, você apenas especifica a propriedade e o valor {key: value} dentro da sua especificação ngFor.

Não é muito diferente da resposta de @ NateMay, exceto que eu explico isso em detalhes relativamente detalhados.

No meu caso, filtrei uma lista não ordenada em algum texto (filterText) que o usuário inseriu na propriedade "label" dos objetos em minha matriz com esse tipo de marcação:

<ul>
  <li *ngFor="let item of _items | filter:{label: filterText}">{{ item.label }}</li>
</ul>

https://long2know.com/2016/11/angular2-filter-pipes/


0

A primeira etapa que você cria o Filter usando @Pipeno seu arquivo component.ts:

your.component.ts

import { Component, Pipe, PipeTransform, Injectable } from '@angular/core';
import { Person} from "yourPath";

@Pipe({
  name: 'searchfilter'
})
@Injectable()
export class SearchFilterPipe implements PipeTransform {
  transform(items: Person[], value: string): any[] {
    if (!items || !value) {
      return items;
    }
    console.log("your search token = "+value);
    return items.filter(e => e.firstName.toLowerCase().includes(value.toLocaleLowerCase()));
  }
}
@Component({
  ....
    persons;

    ngOnInit() {
         //inicial persons arrays
    }
})

E estrutura de dados do objeto Person:

person.ts

export class Person{
    constructor(
        public firstName: string,
        public lastName: string
    ) { }
}

Na sua opinião no arquivo html:

your.component.html

    <input class="form-control" placeholder="Search" id="search" type="text" [(ngModel)]="searchText"/>
    <table class="table table-striped table-hover">
      <colgroup>
        <col span="1" style="width: 50%;">
        <col span="1" style="width: 50%;">
      </colgroup>
      <thead>
        <tr>
          <th>First name</th>
          <th>Last name</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let person of persons | searchfilter:searchText">
          <td>{{person.firstName}}</td>
          <td>{{person.lastName}}</td>
        </tr>
      </tbody>
    </table>

0

Este é o seu array

products: any = [
        {
            "name": "John-Cena",
                    },
        {
            "name": "Brock-Lensar",

        }
    ];

Este é o seu loop ngFor Filtrar por:

<input type="text" [(ngModel)]='filterText' />
    <ul *ngFor='let product of filterProduct'>
      <li>{{product.name }}</li>
    </ul>

Lá estou usando o filterProduct instantâneo de produtos, porque quero preservar meus dados originais. Aqui, o modelo _filterText é usado como uma caixa de entrada. Sempre que houver alguma função do alterador de alterações será chamada. No setFilterText, performProduct é chamado, ele retornará o resultado apenas para aqueles que correspondem à entrada. Estou usando letras minúsculas para não fazer distinção entre maiúsculas e minúsculas.

filterProduct = this.products;
_filterText : string;
    get filterText() : string {
        return this._filterText;
    }

    set filterText(value : string) {
        this._filterText = value;
        this.filterProduct = this._filterText ? this.performProduct(this._filterText) : this.products;

    } 

    performProduct(value : string ) : any {
            value = value.toLocaleLowerCase();
            return this.products.filter(( products : any ) => 
                products.name.toLocaleLowerCase().indexOf(value) !== -1);
        }

0

Depois de pesquisar no Google, me deparei ng2-search-filter. In pegará seu objeto e aplicará o termo de pesquisa a todas as propriedades do objeto que procuram uma correspondência.


0

Eu estava procurando algo para fazer um filtro passar um objeto, então eu posso usá-lo como multi-filtro: Exemplo de filtro múltiplo

eu fiz esta solução de beleza:

filter.pipe.ts

import { PipeTransform, Pipe } from '@angular/core';

@Pipe({
  name: 'filterx',
  pure: false
})
export class FilterPipe implements PipeTransform {
 transform(items: any, filter: any, isAnd: boolean): any {
  let filterx=JSON.parse(JSON.stringify(filter));
  for (var prop in filterx) {
    if (Object.prototype.hasOwnProperty.call(filterx, prop)) {
       if(filterx[prop]=='')
       {
         delete filterx[prop];
       }
    }
 }
if (!items || !filterx) {
  return items;
}

return items.filter(function(obj) {
  return Object.keys(filterx).every(function(c) {
    return obj[c].toLowerCase().indexOf(filterx[c].toLowerCase()) !== -1
  });
  });
  }
}

component.ts

slotFilter:any={start:'',practitionerCodeDisplay:'',practitionerName:''};

componet.html

             <tr>
                <th class="text-center">  <input type="text" [(ngModel)]="slotFilter.start"></th>
                <th class="text-center"><input type="text" [(ngModel)]="slotFilter.practitionerCodeDisplay"></th>
                <th class="text-left"><input type="text" [(ngModel)]="slotFilter.practitionerName"></th>
                <th></th>
              </tr>


 <tbody *ngFor="let item of practionerRoleList | filterx: slotFilter">...
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.