Como Criar Um Componente Reutilizável no Angular - Stack Overflow em Português
Estou com um sistema onde todos os módulos possuem uma tela de listagem de registros padronizada com paginação. Adaptei um código de paginação que achei na Internet para fazer paginação sob demanda. No entanto, ao invés de repetir esse código em todas as telas de listagem gostaria de criar um componente para apenas ser chamado nessas telas. Faço isso da seguinte maneira:
Serviço Adaptado que faz a paginação
export class PagerService {
getPager(totalItems: number, currentPage: number = 0, pageSize: number = 10) {
let totalPages = Math.ceil(totalItems / pageSize);
} else if (currentPage > totalPages) {
let startPage: number, endPage: number;
} else if (currentPage + 3 >= totalPages) {
endPage = currentPage + 3;
let startIndex = (currentPage) * pageSize;
let endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);
let pages = Array.from(Array((endPage + 1) - startPage).keys()).map(i => startPage + i);
import { AppSettings } from './../../settings/app-settings';
import { PageEquipamento } from './../entity/page-equipamento';
import AppHelper from '../../helper/AppHelper';
import { LoadingHugeComponent } from '../../loading/huge/loading-huge.component';
import { SharedDataService } from '../../services/SharedDataService';
import { EquipamentosService } from '../services/equipamentos.service';
import { Equipamento } from '../../entity/equipamento';
import { PagerService } from '../../services/pager.service';
selector: 'app-listar-equipamentos',
templateUrl: './listar-equipamentos.component.html',
styleUrls: ['./listar-equipamentos.component.css'],
export class ListarEquipamentosComponent implements OnInit {
private appHelper: AppHelper = new AppHelper();
public loadingHugeComponent = LoadingHugeComponent;
public listUrls;
//Equipamento Selecionado
public indexEquipamentoSelecionado: number;
public nomeSelecionado: string;
//Page Equipamentos
private subPageEquipamento;
public pageEquipamento: PageEquipamento = new PageEquipamento();
constructor(private titleService: Title, private sharedDataService: SharedDataService,
private equipamentosService: EquipamentosService,
private toastrService: ToastrService,
private pagerService: PagerService
const allowed = ['listarEquipamentos', 'gravarEquipamento'];
this.listUrls = this.appHelper.urlNotAllowed(allowed, environment.urls);
this.loadRegistrosPaginados();
this.subPageEquipamento.unsubscribe();
confirmaExcluirEquipamento(i: number) {
this.indexEquipamentoSelecionado = i;
this.nomeSelecionado = this.pageEquipamento.listaEquipamentos[i].nome;
$('#modalLista').modal('show');
excluirEquipamento() {
this.equipamentosService.excluirEquipamento(this.pageEquipamento.listaEquipamentos[this.indexEquipamentoSelecionado].id).subscribe(
this.toastrService.info(this.pageEquipamento.listaEquipamentos[this.indexEquipamentoSelecionado].nome, ' Excluido com sucesso!');
this.pageEquipamento.listaEquipamentos.splice(this.indexEquipamentoSelecionado, 1);
this.toastrService.error('Não foi possível excluir');
//Carrega os registros paginados
loadRegistrosPaginados() {
this.subPageEquipamento = this.equipamentosService.getEquipamentosPage(AppSettings.RESGISTROS_POR_PAGINA)
this.pageEquipamento.listaEquipamentos = resp.content;
this.pageEquipamento.totalElements = resp.totalElements;
//Gera o HTML da Paginação
this.pager = this.pagerService.getPager(this.pageEquipamento.totalElements, 1, AppSettings.RESGISTROS_POR_PAGINA);
this.pagedItems = this.pageEquipamento.listaEquipamentos.slice(this.pager.startIndex, this.pager.endIndex + 1);
//Método chamado pela paginação
this.subPageEquipamento = this.equipamentosService.getEquipamentosPage(AppSettings.RESGISTROS_POR_PAGINA, page - 1)
this.pageEquipamento.totalElements = resp.totalElements
this.pager = this.pagerService.getPager(this.pageEquipamento.totalElements, page, AppSettings.RESGISTROS_POR_PAGINA);
HTML da Paginação
<div *ngIf="!(pageProposta.listaEquipamentos?.length===0)">
<div *ngFor="let item of pagedItems">{{item.name}}</div>
<a [routerLink]="" (click)="setPage(1)">Primeiro</a>
<li *ngFor="let page of pager.pages" [ngClass]="{active:pager.currentPage === page}">
<a [routerLink]="" (click)="setPage(page)">{{page}}</a>
<a [routerLink]="" (click)="setPage(pager.totalPages)">Último</a>
Usando essa lógica é possível adaptá-la para criar um componente reutilizável para todas a telas de listagem do sistema?
é só vc adicionar a tag <app-listar-equipamentos></app-listar-equipamentos> onde vc quer utilizar esse seu componente
27/02/19 às 20:15
Você quer componentizar o pager ?
28/02/19 às 10:41
Se você quer uma tabela componentizada dá uma olhada nesse meu exemplo: stackblitz.com/edit/… Criei uma tabela que dá pra ser reutilizada de uma maneira bem simples utilizando o ng-template e vc pode adaptar pra deixar com paginação e controle de exclusão de itens e tudo mais...
28/02/19 às 14:21
O problema que estou tendo é com o subscribe dentro do método setPage(), pois quando esse método é chamado pelo HTML eu recarrego a lista de equipamentos (this.pageEquipamento.listaEquipamentos) se eu colocar esse método no componente separado não poderei recarregá-lo...
5/04/19 às 18:46
André, aconselho você a criar um módulo (shared) e dentro desse módulo você criar todos os componentes que serão compartilhados com todo ou a maioria do sistema, por exemplo, na minha aplicação utilizo o módulo shared pra compartilhar mensagens de validações de erro.
Funcionaria mais ou menos da seguinte forma:
módulo shared possui os componentes listar-registros e validar-formulario
Depois para chamar em outros componentes é só você utilizar o selector do seu componente listar-registros.
Obs: não esqueça de exportar o módulo e importar caso seja necessário!
respondida 5/04/19 às 19:14
Entendi, mas o problema que eu estou enfrentando é no método setPage do novo componente que vou criar. Por exemplo, eu iria criar o componente paginação dentro da pasta shared, ok. No html desse componente eu colocaria o HTML que postei acima, contudo ele iria chamar o método setPage(), só que como a paginação é sob demanda eu faço uma nova requisição dentro desse método e como a lista de equipamentos está em outro Component não seria possível carregá-lo... Queria ver se tinha como resolver isso...
5/04/19 às 19:26
Tem muitas formas de escrever, e talvez seja difícil. Primeiramente, vou mais lhe dar alguns lembretes gerais:
Um serviço é um container de estado. Ele só possui dados e não possui nenhum template;
Um componente é um container de estado + um template html. Sendo que esse container de estado pode ser delegado a um serviço (quando o template acessa a variáveis do serviço);
O que torna um serviço especial é o seu comportamento de injeção de dependência; Um serviço tem o seu ciclo de vida controlado por onde você o coloca como "provider" (ler a seção de injeção de dependências da documentação).
O "providedIn: 'root'" injeta o serviço automaticamente como singleton (variavel global). Experimente tirar esse linha da anotação do serviço, vai dar erro. O erro só será solicionado quando você injetar o servico como "provider" em outro componente ou módulo. Ou seja: um serviço não é necessariamente um singleton, ele pode ser acoplado a qualquer coisa.
Se você colocar um serviço no providers de um componente ele é criado e destruído com esse componente. A mesma coisa se colocar no providers de um module. E também há o viewProviders, que torna o serviço disponível também pra todos os componentes filho.
Ok entendendo de como funciona a injeção de dependência, vamos ao seu componente:
Pense no seu componente como uma caixa preta. A responsabilidade dele é fazer paginação de QUALQUER COISA. Ou seja, regra número 1 é que ele não pode ter nenhuma regra de negócio específica da sua aplicação.
Pergunte até onde vai a responsabilidade do seu "componente" (não o componente angular, a "coisa" que você quiser criar). Você pode decidir, por exemplo, que seu "componente" não deve se preocupar com gerar HTML e CSS, mas seu consumidor é que deve cuidar disso. Responsabilidades maiores trazem menos flexibilidade, mas mais facilidade de uso. Responsabilidades menores trazem mais flexiblidade, mas menos coisa pronta.
Se o seu componente não for gerar html e CSS, ele pode ser um serviço que expõe variáveis e funções úteis pra um consumidor então os usarem em um componente. Exemplo: export: "página Atual", "próximaPágina()", "irParaPágina()". E o consumidor que decide se o coloca em um botão ou qualquer outra coisa.
No outro caso, ao criar componentes, o uso de @Input e @Output são chaves importantes pra desacoplamento. Por exemplo, você pode escrever um componente de paginação que não tem a responsabilidade de espeficificar COMO a página será atualizada. Este componente pode emitir um @Output quando se clica em um botão, daí o componente pai é que vai decidir o que fazer com esse evento. Desta forma, seu componente de paginação fica mais genérico, obedecendo melhor ao princípio de responsabilidade única.
Ambos o uso de Providers, Output ou Input remetem ao mesmo problema: Em qual componente devo guardar meu estado? Em qual componente deve ficar qual variável? No pai? No filho? Este é um problema essencial de todas as 3 frameworks famosas do momento. Aprendendo isso no Angular, vc de quebra aprende coisas importantes pra usar qualquer outra framework.
respondida 28/11/19 às 3:42
Esta não é a resposta que você está procurando? Pesquise outras perguntas com a tag angular angular-6 componentes component ou faça sua própria pergunta.