Componentes angulares com conteúdo embutido

Ao criar novos componentes ao desenvolver no Angular, você se esforça para criá-los de forma que eles possam ser reutilizados várias vezes. Assim como no desenvolvimento de software, um programador se esforça para tornar seu código o mais reutilizável possível. Ao mesmo tempo, quero ter componentes flexíveis, mas não muito complexos.



Como regra, os componentes precisam ser feitos o mais estúpido possível, para que seja mais fácil manter e testar. Mas, ao mesmo tempo, eles são personalizáveis ​​e flexíveis, para que você possa reutilizá-los muitas vezes e não se envolver em componentes de clonagem que são semelhantes visual e funcionalmente, mas ainda diferem em algo. Ou não adicione vários parâmetros aos componentes, com base nos quais habilitar ou desabilitar qualquer comportamento do componente, mas que de fato serão usados ​​em 1 em cada 100 casos.

Criar um submarino, que deve afundar até o fundo do mar azul sem risco para a vida da tripulação e modificá-lo antes de voar pelo céu azul não é uma tarefa fácil.

Um componente angular é a menor unidade da interface do usuário que deve executar uma tarefa simples e nada mais. Criar componentes para todas as ocasiões é uma prática ruim. Portanto, você precisa encontrar um compromisso entre flexibilidade e simplicidade.

Suponha que você deseje criar um componente que consiste em algum tipo de wrapper, dentro do qual existe um cabeçalho, algum tipo de opção e algum conteúdo embaixo deles. Algo assim:



Todo o componente, que será chamado de widget, é destacado em verde. A opção do cabeçalho é destacada em vermelho e o conteúdo é destacado em azul. Angular é uma estrutura incrivelmente poderosa; criar um componente semelhante ao da imagem é uma tarefa muito trivial para Angular.

Mas e se esse componente for mais flexível, por exemplo, para que o conteúdo seja alterado dependendo dos parâmetros do componente do widget?

Você pode resolver a representação externa do conteúdo com base no parâmetro widget, por exemplo, usando a diretiva estrutural ngIf . Você pode alternar entre diferentes visões. E se houver muitos envios, você poderá usar outra diretiva estrutural do ngSwitch .

E se visualizações diferentes responderem de maneira diferente às ações do usuário? Em seguida, o código do componente também terá várias instruções condicionais. Mas o código, no qual existem muitas instruções condicionais, com o tempo torna-se difícil manter, corrigir erros ou expandir a funcionalidade ...

Você pode criar um componente de widget de forma a receber qualquer conteúdo, mas ao mesmo tempo lança os valores selecionados do painel de filtro nos componentes da área de conteúdo. E também gostaria de poder encaminhar parâmetros do componente pai do widget para o conteúdo, sem afetar o próprio componente do widget. Para resolver esse problema, você pode usar a maravilhosa diretiva ngTemplateOutlet , que permitirá "resolver" a representação visual do componente. Para informações adicionais, você pode consultar a documentação , embora, na minha opinião, todo o seu poder não seja mostrado lá.

Nesse caso, o componente do widget pode ser representado da seguinte maneira:

// widget.component.ts … private widgetContentTemplate: TemplateRef<any>; //      @ContentChild(WidgetContentTemplateDirective, { read: TemplateRef }) set WidgetContentTemplate(value: TemplateRef<any>) { this.widgetContentTemplate = value; } get WidgetContentTemplate(): TemplateRef<any> { return this.widgetContentTemplate; } … 

 <!-- widget.component.html --><div class="widget__content"> <!--      ,      context.   ,     --> <ng-container *ngTemplateOutlet="WidgetContentTemplate || DefaultWidgetContentTemplate; context: { post: SelectedPost }"> </ng-container> </div> <ng-template #DefaultWidgetContentTemplate> <div>[    ]</div> </ng-template> 

A diretiva ngTemplateOutlet aceita um objeto TemplateRef que é lido no componente usando @ContentChild. Para fazer isso, você precisa criar uma diretiva simples. Aqui está o código dela:

 // widget-content-template.directive.ts import { Directive, TemplateRef } from '@angular/core'; @Directive({ selector: '[appWidgetContentTemplate]' }) export class WidgetContentTemplateDirective { get Template(): TemplateRef<any> { return this.template; } constructor(private readonly template: TemplateRef<any>) {} } 

Os parâmetros da opção de widget podem ser passados ​​para o conteúdo usando o objeto de contexto. Para que os parâmetros do contexto sejam lidos corretamente pelo componente, é necessário no componente pai, no nosso caso é AppComponent, não se esqueça de descrevê-los da seguinte forma:

 <!-- app.component.html --> <app-widget-component Title="  (  )"> <!-- let-post="post" ,         --> <ng-template appWidgetContentTemplate let-post="post"> <app-post-view [Post]="post"></app-post-view> </ng-template> </app-widget-component> <br> <br> <app-widget-component Title="  (  )"> <!--  let-post="post"     ,  ShowPostInfo  AppComponent --> <ng-template appWidgetContentTemplate let-post="post"> <app-post-view [Post]="post" [ShowPostInfo]="ShowPostInfo"></app-post-view> </ng-template> </app-widget-component> 

Portanto, temos um componente de widget que aceita e exibe qualquer conteúdo, enquanto o próprio componente de widget não precisa saber nada sobre o conteúdo. Simplesmente encaminha as opções de chave. Leia-os ou não é uma questão de conteúdo.



A versão completa do código pode ser vista aqui .

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


All Articles