Injetando componentes no Angular através de diretivas
Em nossa aplicação Angular nós precisamos criar um componente de múltipla seleção. Ao criar componentes genéricos, é importante que eles sejam bastante flexíveis para que atendam os mais diversos cenários.
Uma questão que devia ser levada em conta era a performance do componente, uma vez que muitos dados poderiam ser carregados nele. Sabendo disso, deixamos a responsabilidade para o desenvolvedor que fosse utilizá-lo. O carregamento dos dados somente seria feito quando o usuário clicasse para abrir a lista dos dados disponíveis para seleção.
Para isso foi criado um Output que serviria como um EventEmitter. Ao abrir o componente, este evento é emitido para que os dados possam ser carregados.
Foi necessário utilizar este componente em vários lugares da aplicação, e os dados a serem carregados poderiam vir de diferentes API’s. A forma mais simples seria a de chamar a API quando o Output emitisse um valor.
No entanto, em todos os lugares em que o componente for utilizado, vamos precisar utilizar este mesmo código, infringindo o princípio DRY (Don’t Repeat Yourself).
Wrapper Component
Uma estratégia para tornar esta operação reutilizável é a de criar um componente de negócio que serviria como um Wrapper para o componente genérico de múltipla seleção, assim é possível encapsular a chamada para a API dentro dele.
A estratégia funciona, porém temos dois problemas:
- Ao criar um componente de negócio que encapsula o componente genérico, perdemos toda a flexibilidade dele. Para passarmos valores dinâmicos precisamos duplicar praticamente todos os seus Inputs. Além disso perdemos a referência do componente, precisaremos sempre expor o componente genérico com o ViewChild.
- Redundância de código: para que os formulários acessem o valor do componente precisamos sempre criar o ControlValueAcessor destinado a ele.
Solução: criar uma diretiva com Element Injector
Sabemos que as diretivas são classes que adicionam comportamentos nos elementos do template. Portanto, não precisamos de um componente com um novo template, mas sim novos comportamentos dentro do mesmo template. O Angular oferece um recurso poderoso chamado Element Injector, onde componentes e diretivas podem compartilhar um mesmo Injector. Isso significa que podemos criar uma diretiva de negócio que injeta o nosso componente genérico de múltipla seleção.
Temos agora total liberdade para adicionar comportamentos dentro da diretiva e de quebra resolvemos os dois problemas mencionados anteriormente, já que para utilizá-la estamos fazendo o uso da composição. Veja como deixamos o HTML simples e flexível.
Reatividade com RxJS
No início deste artigo, mencionei que o componente de múltipla seleção expõe um Output que emite um evento toda a vez que o mesmo é aberto. Você sabia que um EventEmitter nada mais é do que um Observable? Vamos aproveitar então para nos inscrever neste Observable. Toda vez que ele emitir um evento, encadeamos com o operador switchMap do RxJS a chamada HTTP para o carregamento dos dados disponíveis.
Com este código reativo fica muito fácil encadear outros operadores do RxJS afim de obter outros comportamentos. Podemos por exemplo atribuir um comportamento de loading ou criar uma estratégia para cachear os dados da API.
Conclusão
Espero que este artigo tenha dado uma visão maior de como podemos utilizar alguns recursos do Angular como as diretivas atreladas ao Element Injector para escrevermos códigos mais desacoplados, reutilizáveis e com maior performance. Até a próxima!