Angular: Crie um componente de caixa de seleção múltipla adequado para reutilização

Vamos criar um componente Angular para criar um conjunto de caixas de seleção de um grupo lógico específico. O componente será escrito com idéias de reutilização. O que isso significa? Aqui está um exemplo abaixo:

Imagine que você tem a tarefa de editar usuários. Ao editar, um formulário com todos os campos geralmente é aberto. Um usuário pode ter uma ou várias funções na lista de "Adimin", "Diretor", "Professor", "Aluno".

Para implementar a múltipla escolha de funções, decidiu-se desenhar no formulário uma caixa de seleção para cada função. Ao marcar ou desmarcar as funções do usuário, será alterado.

Primeiro, vamos criar um componente pai (ou seja, uma página para o formulário) que já conterá nosso componente de grupo de caixas de seleção .

export class AppComponent implements OnInit { private userRoles = [ { id: 1, name: 'Admin' }, { id: 2, name: 'Director' }, { id: 3, name: 'Professor' }, { id: 4, name: 'Student' } ]; public userModel = { id: 0, name: "", roles: [] }; constructor() { } ngOnInit(): void { } } 

Como você pode ver aqui, criei um código rígido de todas as funções possíveis, mas em um aplicativo real, as funções provavelmente serão solicitadas no banco de dados. Para simular nosso HTTP ao servidor, atribuai os mesmos valores a outra variável com um pequeno atraso.

 //app.component.ts userRolesOptions = new Array<any>(); ngOnInit(): void { setTimeout(() => { this.userRolesOptions = this.userRoles; }, 1000); //     1  } 

Agora vamos começar a criar um componente de grupo de caixas de seleção generalizado, que pode ser reutilizado sem problemas em todos os casos quando um grupo da caixa de seleção é necessário.

Primeiro, precisamos dessa classe CheckboxItem.ts

 export class CheckboxItem { value: string; label: string; checked: boolean; constructor(value: any, label: any, checked?: boolean) { this.value = value; this.label = label; this.checked = checked ? checked : false; } } 

Ele será usado pelo CheckboxComponent para renderizar todas as opções possíveis (no nosso caso, são funções) e salvar do estado (a opção está selecionada ou não). Observe que a propriedade “marcada” é um parâmetro opcional no construtor e será padronizada como false, ou seja, todos os valores não serão selecionados primeiro. Isso é adequado quando criamos um novo usuário sem uma única função.

Em seguida, modificaremos levemente nossa função, simulando a solicitação do servidor, para que possamos mapear entre a resposta JSON e a Matriz
 userRolesOptions = new Array<CheckboxItem>(); ngOnInit(): void { setTimeout(() => { this.userRolesOptions = this.userRoles.map(x => new CheckboxItem(x.id, x.name)); }, 1000); } 

Não importa qual estrutura JSON o servidor retornará para nós. Cada caixa de seleção HTML sempre tem um valor e uma descrição. No nosso caso, mapeamos “id” com “value” e “name” com “label”. O valor será usado como uma chave ou ID para a opção, e label é apenas uma sequência de descrição que o usuário lê.

O próximo passo é criar um CheckboxGroupComponent. Ele se parece com isso:

 @Component({ selector: 'checkbox-group', templateUrl: './checkbox-group.component.html', styleUrls: ['./checkbox-group.component.css'] }) export class CheckboxGroupComponent implements OnInit { @Input() options = Array<CheckboxItem>(); constructor() { } ngOnInit() {} } 

Este não é um tutorial angular, por isso não explicarei as especificidades da estrutura. Quem precisa ler a documentação oficial.

A propriedade @Input chamada options conterá uma lista de todos os valores possíveis que não são selecionados por padrão. Nosso modelo de componente HTML renderizará tantas caixas de seleção quanto esta lista contiver.

Este é o html para CheckboxGroupComponent:

 <div *ngFor=”let item of options”> <input type=”checkbox” [(ngModel)]=”item.checked”>{{item.label}} </div> 

Observe que eu usei o ngModel para vincular cada propriedade de item "marcado" na lista de opções .

A etapa final é adicionar nosso componente recém-criado ao modelo AppComponent pai.

 // somewhere in AppComponent html template <checkbox-group [options]=”userRolesOptions”></checkbox-group> 

O resultado deve ser assim:

imagem

Para obter todas as opções atualmente selecionadas, criaremos um evento Output que, com qualquer clique em uma das caixas de seleção, retornará nossa lista das selecionadas. Algo assim: [1,2,4]

No modelo CheckboxGroupComponent, associamos o evento de mudança à nova função.

 <div *ngFor=”let item of options”> <input type=”checkbox” [(ngModel)]=”item.checked” (change)=”onToggle()”>{{item.label}} </div> 

É hora de implementar esta mesma função:

 export class CheckboxGroupComponent implements OnInit { @Input() options = Array<CheckboxItem>(); @Output() toggle = new EventEmitter<any[]>(); constructor() {} ngOnInit(){} onToggle() { const checkedOptions = this.options.filter(x => x.checked); this.selectedValues = checkedOptions.map(x => x.value); this.toggle.emit(checkedOptions.map(x => x.value)); } } 

Inscreva-se neste evento (propriedade Output com o nome toggle ) no modelo AppComponent.

 <checkbox-group [options]=”userRolesOptions” (toggle)=”onRolesChange($event)”></checkbox-group> 

E atribua o resultado do retorno (funções selecionadas) no userModel.

 export class CheckboxGroupComponent implements OnInit { //..  onRolesChange(value) { this.userModel.roles = value; console.log('Model role:' , this.userModel.roles); } } 

Agora, a cada clique na caixa de seleção, você verá uma lista de funções selecionadas no console. Mais precisamente, a identificação deles. Por exemplo, se eu escolher as funções Administrador e Professor , recebo "Funções de modelo: (2) [1, 3]".

O componente está quase completo e pronto para reutilização. A última coisa que resta é dar suporte à inicialização do grupo de caixas de seleção. Isso será necessário no caso em que faremos a edição do usuário. Antes disso, precisamos fazer uma solicitação ao servidor para obter a lista atual de funções de usuário e inicializar CheckboxGroupComponent.

Temos duas maneiras de fazer isso. O primeiro é usar o construtor da classe CheckboxItem e usar o parâmetro opcional "marcado". No local onde fizemos o mapeamento.

 //AppComponent.ts setTimeout(() => { this.userRolesOptions = this.userRoles.map(x => new CheckboxItem(x.id, x.name, true)); }, 1000); //          

A segunda maneira é adicionar outra lista de valores selecionados para inicializar nosso componente.

 <checkbox-group [options]=”userRolesOptions” [selectedValues]=”userModel.roles” (toggle)=”onRolesChange($event)”></checkbox-group> 

Vamos imaginar que já fizemos uma solicitação para o usuário atual e um modelo com três funções veio do banco de dados.

 //AppComponent.ts public userModel = { id: 1, name: 'Vlad', roles: [1,2,3] }; constructor() { } //rest of the code 

No CheckboxGroupComponent, inicializamos todas as propriedades "marcadas" de cada caixa de seleção para true se o ID da função estiver contido na lista selectedValues .

 //CheckboxGroupComponent.ts ngOnInit() { this.selectedValues.forEach(value => { const element = this.options.find(x => x.value === value); if (element) { element.checked = true; } }); } 

Como resultado, você deve obter o seguinte resultado:

imagem
Aqui usei estilos do Material Angular

Na inicialização, haverá um atraso de um segundo antes que o Angular desenhe todas as caixas de seleção na página. Isso simula o tempo gasto no carregamento de funções do banco de dados.

É importante observar que você pode obter todas as funções selecionadas inscrevendo-se em um evento (alternar) ou simplesmente usar a propriedade “marcada” em cada objeto de item da lista userRolesOptions localizada no componente pai . Isso ocorre porque o link para a lista é passado via @Input (ligação) e todas as alterações no objeto serão sincronizadas.

 const checkedOptions = this.userRolesOptions.filter(x => x.checked); 

Esse componente pode ser estilizado como você desejar e usado para qualquer tarefa em que a seleção múltipla seja necessária.

Obrigado por ler este artigo! Espero que você tenha gostado de criar o componente Angular para idéias de reutilização.

PS: Se o artigo for popular, publicarei a segunda pequena parte, onde o mesmo exemplo é escrito usando Formas Reativas Angulares.

Source: https://habr.com/ru/post/pt417137/


All Articles