Estender um Componente principal extend-component
Saiba como estender um Componente principal existente para ser usado com o Editor de SPA AEM. AEM Entender como estender um componente existente é uma técnica poderosa para personalizar e expandir os recursos de uma implementação do Editor de SPA.
Objetivo
- Estender um Componente principal existente com propriedades e conteúdo adicionais.
- Entenda o básico da Herança de componentes com o uso de
sling:resourceSuperType
. - Saiba como usar o Padrão de delegação para Modelos do Sling para reutilizar a lógica e a funcionalidade existentes.
O que você vai criar
Neste capítulo, um novo componente Card
é criado. O componente Card
estende o Componente principal da imagem, adicionando campos de conteúdo adicionais, como um Título e um botão de Chamada para Ação, para executar a função de um teaser para outro conteúdo no SPA.
Card
, dependendo dos requisitos do projeto. É sempre recomendável usar Componentes principais diretamente quando possível.Pré-requisitos
Revise as ferramentas e instruções necessárias para configurar um ambiente de desenvolvimento local.
Obter o código
-
Baixe o ponto de partida para este tutorial pelo Git:
code language-shell $ git clone git@github.com:adobe/aem-guides-wknd-spa.git $ cd aem-guides-wknd-spa $ git checkout Angular/extend-component-start
-
Implante a base de código em uma instância de AEM local usando Maven:
code language-shell $ mvn clean install -PautoInstallSinglePackage
Se estiver usando o AEM 6.x, adicione o perfil
classic
:code language-shell $ mvn clean install -PautoInstallSinglePackage -Pclassic
-
Instale o pacote concluído para o site de referência WKND tradicional. As imagens fornecidas pelo site de referência WKND são reutilizadas no SPA WKND. O pacote pode ser instalado usando o Gerenciador de Pacotes do AEM.
do Gerenciador de Pacotes
Você sempre pode exibir o código concluído em GitHub ou conferir o código localmente alternando para a ramificação Angular/extend-component-solution
.
Implementação inicial do Cartão Inspect
Um componente Cartão inicial foi fornecido pelo código inicial do capítulo. O Inspect é o ponto de partida para a implementação do Cartão.
-
No IDE de sua escolha, abra o módulo
ui.apps
. -
Navegue até
ui.apps/src/main/content/jcr_root/apps/wknd-spa-angular/components/card
e exiba o arquivo.content.xml
.code language-xml <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" jcr:primaryType="cq:Component" jcr:title="Card" sling:resourceSuperType="wknd-spa-angular/components/image" componentGroup="WKND SPA Angular - Content"/>
A propriedade
sling:resourceSuperType
aponta parawknd-spa-angular/components/image
, indicando que o componenteCard
herda a funcionalidade do componente de Imagem SPA WKND. -
Inspect o arquivo
ui.apps/src/main/content/jcr_root/apps/wknd-spa-angular/components/image/.content.xml
:code language-xml <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" jcr:primaryType="cq:Component" jcr:title="Image" sling:resourceSuperType="core/wcm/components/image/v2/image" componentGroup="WKND SPA Angular - Content"/>
Observe que
sling:resourceSuperType
aponta paracore/wcm/components/image/v2/image
. Isso indica que o componente de Imagem SPA WKND herda a funcionalidade da Imagem do componente principal.Também conhecido como Padrão de proxy, a herança de recursos do Sling é um padrão de design avançado que permite que os componentes secundários herdem funcionalidade e estendam/substituam o comportamento quando desejado. A herança do Sling oferece suporte a vários níveis de herança, de modo que, por fim, o novo componente
Card
herda a funcionalidade da Imagem do componente principal.Muitas equipes de desenvolvimento se esforçam para ser D.R.Y. (não se repita). A herança por Sling torna isso possível com o AEM.
-
Abaixo da pasta
card
, abra o arquivo_cq_dialog/.content.xml
.Este arquivo é a definição de Caixa de Diálogo de Componente para o componente
Card
. Se estiver usando a herança do Sling, é possível usar os recursos do Sling Resource Merger para substituir ou estender partes da caixa de diálogo. Neste exemplo, uma nova guia foi adicionada à caixa de diálogo para capturar dados adicionais de um autor para preencher o componente Cartão.Propriedades como
sling:orderBefore
permitem que um desenvolvedor escolha onde inserir novas guias ou campos de formulário. Nesse caso, a guiaText
é inserida antes da guiaasset
. Para usar totalmente o Sling Resource Merger, é importante conhecer a estrutura original do nó de diálogo da caixa de diálogo do componente de Imagem. -
Abaixo da pasta
card
, abra o arquivo_cq_editConfig.xml
. Esse arquivo determina o comportamento de arrastar e soltar na interface de criação do AEM. Ao estender o componente de Imagem, é importante que o tipo de recurso corresponda ao próprio componente. Revise o nó<parameters>
:code language-xml <parameters jcr:primaryType="nt:unstructured" sling:resourceType="wknd-spa-angular/components/card" imageCrop="" imageMap="" imageRotate=""/>
A maioria dos componentes não requer um
cq:editConfig
. A Imagem e os descendentes secundários do componente de Imagem são exceções. -
No IDE, alterne para o módulo
ui.frontend
, navegando paraui.frontend/src/app/components/card
: -
Inspect o arquivo
card.component.ts
.O componente já foi esvaziado para mapear para o Componente AEM
Card
usando a função padrãoMapTo
.code language-js MapTo('wknd-spa-angular/components/card')(CardComponent, CardEditConfig);
Revise os três parâmetros
@Input
na classe parasrc
,alt
etitle
. Esses são valores JSON esperados do componente AEM que são mapeados para o componente Angular. -
Abra o arquivo
card.component.html
:code language-html <div class="card" *ngIf="hasContent"> <app-image class="card__image" [src]="src" [alt]="alt" [title]="title"></app-image> </div>
Neste exemplo, optamos por reutilizar o componente de Imagem de Angular existente
app-image
simplesmente passando os parâmetros@Input
decard.component.ts
. Posteriormente no tutorial, propriedades adicionais são adicionadas e exibidas.
Atualizar a política do modelo
Com esta implementação inicial de Card
, analise a funcionalidade no Editor de SPA AEM. Para ver o componente Card
inicial, é necessário atualizar a diretiva Modelo.
-
Implante o código inicial em uma instância local do AEM, se você ainda não tiver:
code language-shell $ cd aem-guides-wknd-spa $ mvn clean install -PautoInstallSinglePackage
-
Navegue até o Modelo de página SPA em http://localhost:4502/editor.html/conf/wknd-spa-angular/settings/wcm/templates/spa-page-template/structure.html.
-
Atualize a política do Contêiner de Layout para adicionar o novo componente
Card
como um componente permitido:Salve as alterações na política e observe o componente
Card
como um componente permitido:
Componente Cartão inicial do autor
Em seguida, crie o componente Card
usando o Editor SPA AEM.
-
Navegue até http://localhost:4502/editor.html/content/wknd-spa-angular/us/en/home.html.
-
No modo
Edit
, adicione o componenteCard
aLayout Container
: -
Arraste e solte uma imagem do Localizador de ativos no componente
Card
: -
Abra a caixa de diálogo do componente
Card
e observe a adição de uma guia Texto. -
Insira os seguintes valores na guia Texto:
Caminho do cartão - escolha uma página abaixo da página inicial do SPA.
Texto CTA - "Leia mais"
Título do cartão - deixe em branco
Obter título da página vinculada - marque a caixa de seleção para indicar verdadeiro.
-
Atualize a guia Metadados do ativo para adicionar valores para Texto alternativo e Legenda.
No momento, nenhuma alteração adicional é exibida após a atualização da caixa de diálogo. Para expor os novos campos ao Componente de Angular, precisamos atualizar o Modelo do Sling para o componente
Card
. -
Abra uma nova guia e navegue até CRXDE-Lite. Inspect os nós de conteúdo abaixo de
/content/wknd-spa-angular/us/en/home/jcr:content/root/responsivegrid
para localizar o conteúdo do componenteCard
.Observe que as propriedades
cardPath
,ctaText
,titleFromPage
são mantidas pela caixa de diálogo.
Atualizar modelo Sling do cartão
Para expor os valores da caixa de diálogo do componente para o componente do Angular, precisamos atualizar o Modelo do Sling que preenche o JSON para o componente Card
. Também temos a oportunidade de implementar duas partes da lógica de negócios:
- Se
titleFromPage
for true, retorna o título da página especificada porcardPath
; caso contrário, retorna o valor de textfieldcardTitle
. - Retorna a data da última modificação da página especificada por
cardPath
.
Retorne ao IDE de sua escolha e abra o módulo core
.
-
Abra o arquivo
Card.java
emcore/src/main/java/com/adobe/aem/guides/wknd/spa/angular/core/models/Card.java
.Observe que a interface
Card
estende atualmentecom.adobe.cq.wcm.core.components.models.Image
e, portanto, herda os métodos da interfaceImage
. A interfaceImage
já estende a interfaceComponentExporter
, o que permite que o Modelo Sling seja exportado como JSON e mapeado pelo editor de SPA. Portanto, não precisamos estender explicitamente a interfaceComponentExporter
como fizemos no capítulo Componente personalizado. -
Adicione os seguintes métodos à interface:
code language-java @ProviderType public interface Card extends Image { /*** * The URL to populate the CTA button as part of the card. * The link should be based on the cardPath property that points to a page. * @return String URL */ public String getCtaLinkURL(); /*** * The text to display on the CTA button of the card. * @return String CTA text */ public String getCtaText(); /*** * The date to be displayed as part of the card. * This is based on the last modified date of the page specified by the cardPath * @return */ public Calendar getCardLastModified(); /** * Return the title of the page specified by cardPath if `titleFromPage` is set to true. * Otherwise return the value of `cardTitle` * @return */ public String getCardTitle(); }
Esses métodos são expostos por meio da API do modelo JSON e passados para o componente Angular.
-
Abrir
CardImpl.java
. Esta é a implementação da interfaceCard.java
. Esta implementação foi parcialmente removida para acelerar o tutorial. Observe o uso das anotações@Model
e@Exporter
para garantir que o Modelo do Sling possa ser serializado como JSON por meio do Exportador de modelos do Sling.CardImpl.java
também usa o padrão de Delegação para Modelos Sling para evitar a regravação da lógica do Componente principal de imagem. -
Observe as seguintes linhas:
code language-java @Self @Via(type = ResourceSuperType.class) private Image image;
A anotação acima instancia um objeto de Imagem chamado
image
com base na herançasling:resourceSuperType
do componenteCard
.code language-java @Override public String getSrc() { return null != image ? image.getSrc() : null; }
Portanto, é possível simplesmente usar o objeto
image
para implementar métodos definidos pela interfaceImage
, sem precisar gravar a lógica. Esta técnica é usada paragetSrc()
,getAlt()
egetTitle()
. -
Em seguida, implemente o método
initModel()
para iniciar uma variável privadacardPage
com base no valor decardPath
code language-java @PostConstruct public void initModel() { if(StringUtils.isNotBlank(cardPath) && pageManager != null) { cardPage = pageManager.getPage(this.cardPath); } }
O
@PostConstruct initModel()
é chamado quando o Modelo Sling é inicializado, portanto, é uma boa oportunidade para inicializar objetos que podem ser usados por outros métodos no modelo.pageManager
é um dos vários objetos globais com suporte de Java™ disponibilizados para Modelos Sling através da anotação@ScriptVariable
. O método getPage pega um caminho e retorna um objeto AEM Page ou é nulo se o caminho não apontar para uma página válida.Isso inicializa a variável
cardPage
, que é usada por outros novos métodos para retornar dados sobre a página vinculada subjacente. -
Revise as variáveis globais já mapeadas para as propriedades JCR salvas na caixa de diálogo do autor. A anotação
@ValueMapValue
é usada para executar o mapeamento automaticamente.code language-java @ValueMapValue private String cardPath; @ValueMapValue private String ctaText; @ValueMapValue private boolean titleFromPage; @ValueMapValue private String cardTitle;
Essas variáveis são usadas para implementar os métodos adicionais para a interface
Card.java
. -
Implementar os métodos adicionais definidos na interface
Card.java
:code language-java @Override public String getCtaLinkURL() { if(cardPage != null) { return cardPage.getPath() + ".html"; } return null; } @Override public String getCtaText() { return ctaText; } @Override public Calendar getCardLastModified() { if(cardPage != null) { return cardPage.getLastModified(); } return null; } @Override public String getCardTitle() { if(titleFromPage) { return cardPage != null ? cardPage.getTitle() : null; } return cardTitle; }
note note NOTE Você pode exibir o CardImpl.java concluído aqui. -
Abra uma janela de terminal e implante apenas as atualizações para o módulo
core
usando o perfil MavenautoInstallBundle
do diretóriocore
.code language-shell $ cd core/ $ mvn clean install -PautoInstallBundle
Se estiver usando o AEM 6.x, adicione o perfil
classic
. -
Exiba a resposta do modelo JSON em: http://localhost:4502/content/wknd-spa-angular/us/en.model.json e pesquise por
wknd-spa-angular/components/card
:code language-json "card": { "ctaText": "Read More", "cardTitle": "Page 1", "title": "Woman chillaxing with river views in Australian bushland", "src": "/content/wknd-spa-angular/us/en/home/_jcr_content/root/responsivegrid/card.coreimg.jpeg/1595190732886/adobestock-216674449.jpeg", "alt": "Female sitting on a large rock relaxing in afternoon dappled light the Australian bushland with views over the river", "cardLastModified": 1591360492414, "ctaLinkURL": "/content/wknd-spa-angular/us/en/home/page-1.html", ":type": "wknd-spa-angular/components/card" }
Observe que o modelo JSON é atualizado com pares de chave/valor adicionais após a atualização dos métodos no Modelo Sling
CardImpl
.
Atualizar componente do Angular
Agora que o modelo JSON foi preenchido com novas propriedades para ctaLinkURL
, ctaText
, cardTitle
e cardLastModified
, podemos atualizar o componente Angular para exibi-las.
-
Retorne ao IDE e abra o módulo
ui.frontend
. Como opção, inicie o servidor de desenvolvimento do webpack a partir de uma nova janela do terminal para ver as alterações em tempo real:code language-shell $ cd ui.frontend $ npm install $ npm start
-
Abrir
card.component.ts
emui.frontend/src/app/components/card/card.component.ts
. Adicionar as@Input
anotações adicionais para capturar o novo modelo:code language-diff export class CardComponent implements OnInit { @Input() src: string; @Input() alt: string; @Input() title: string; + @Input() cardTitle: string; + @Input() cardLastModified: number; + @Input() ctaLinkURL: string; + @Input() ctaText: string;
-
Adicione métodos para verificar se a Chamada para Ação está pronta e para retornar uma cadeia de caracteres de data/hora com base na entrada
cardLastModified
:code language-js export class CardComponent implements OnInit { ... get hasCTA(): boolean { return this.ctaLinkURL && this.ctaLinkURL.trim().length > 0 && this.ctaText && this.ctaText.trim().length > 0; } get lastModifiedDate(): string { const lastModifiedDate = this.cardLastModified ? new Date(this.cardLastModified) : null; if (lastModifiedDate) { return lastModifiedDate.toLocaleDateString(); } return null; } ... }
-
Abra
card.component.html
e adicione a seguinte marcação para exibir o título, o plano de ação e a data da última modificação:code language-html <div class="card" *ngIf="hasContent"> <app-image class="card__image" [src]="src" [alt]="alt" [title]="title"></app-image> <div class="card__content"> <h2 class="card__title"> {{cardTitle}} <span class="card__lastmod" *ngIf="lastModifiedDate">{{lastModifiedDate}}</span> </h2> <div class="card__action-container" *ngIf="hasCTA"> <a [routerLink]="ctaLinkURL" class="card__action-link" [title]="ctaText"> {{ctaText}} </a> </div> </div> </div>
As regras de acesso já foram adicionadas em
card.component.scss
para estilizar o título, o plano de ação e a data da última modificação.note note NOTE Você pode exibir o código do componente do cartão de Angular concluído aqui. -
Implante as alterações completas no AEM a partir da raiz do projeto usando o Maven:
code language-shell $ cd aem-guides-wknd-spa $ mvn clean install -PautoInstallSinglePackage
-
Navegue até http://localhost:4502/editor.html/content/wknd-spa-angular/us/en/home.html para ver o componente atualizado:
-
Você deve ser capaz de recriar o conteúdo existente para criar uma página semelhante ao seguinte:
Parabéns. congratulations
Parabéns, você aprendeu a estender um componente AEM e como os Modelos e caixas de diálogo do Sling funcionam com o modelo JSON.
Você sempre pode exibir o código concluído em GitHub ou conferir o código localmente alternando para a ramificação Angular/extend-component-solution
.