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

  1. Estender um Componente principal existente com propriedades e conteúdo adicionais.
  2. Entenda o básico da Herança de componentes com o uso de sling:resourceSuperType.
  3. 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.

Criação Final do Componente de Cartão

NOTE
Em uma implementação real, pode ser mais apropriado simplesmente usar o Componente de Teaser do que estender o Componente Principal da Imagem para criar um componente 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

  1. 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
    
  2. 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
    
  3. 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.

    Instalar wknd.all 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.

  1. No IDE de sua escolha, abra o módulo ui.apps.

  2. Navegue até ui.apps/src/main/content/jcr_root/apps/wknd-spa-angular/components/card e exiba o arquivo .content.xml.

    Início da definição de AEM do Componente do Cartão

    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 para wknd-spa-angular/components/image, indicando que o componente Card herda a funcionalidade do componente de Imagem SPA WKND.

  3. 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 para core/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.

  4. 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 guia Text é inserida antes da guia asset. 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.

  5. 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.

  6. No IDE, alterne para o módulo ui.frontend, navegando para ui.frontend/src/app/components/card:

    Início do Componente do Angular

  7. Inspect o arquivo card.component.ts.

    O componente já foi esvaziado para mapear para o Componente AEM Card usando a função padrão MapTo.

    code language-js
    MapTo('wknd-spa-angular/components/card')(CardComponent, CardEditConfig);
    

    Revise os três parâmetros @Input na classe para src, alt e title. Esses são valores JSON esperados do componente AEM que são mapeados para o componente Angular.

  8. 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 de card.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.

  1. 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
    
  2. 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.

  3. Atualize a política do Contêiner de Layout para adicionar o novo componente Card como um componente permitido:

    Atualizar política de Contêiner de Layout

    Salve as alterações na política e observe o componente Card como um componente permitido:

    Componente do cartão como um componente permitido

Componente Cartão inicial do autor

Em seguida, crie o componente Card usando o Editor SPA AEM.

  1. Navegue até http://localhost:4502/editor.html/content/wknd-spa-angular/us/en/home.html.

  2. No modo Edit, adicione o componente Card a Layout Container:

    Inserir novo componente

  3. Arraste e solte uma imagem do Localizador de ativos no componente Card:

    Adicionar imagem

  4. Abra a caixa de diálogo do componente Card e observe a adição de uma guia Texto.

  5. Insira os seguintes valores na guia Texto:

    Guia Componente de 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.

  6. 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.

  7. 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 componente Card.

    Propriedades do componente CRXDE-Lite

    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 por cardPath; caso contrário, retorna o valor de textfield cardTitle.
  • 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.

  1. Abra o arquivo Card.java em core/src/main/java/com/adobe/aem/guides/wknd/spa/angular/core/models/Card.java.

    Observe que a interface Card estende atualmente com.adobe.cq.wcm.core.components.models.Image e, portanto, herda os métodos da interface Image. A interface Image já estende a interface ComponentExporter, o que permite que o Modelo Sling seja exportado como JSON e mapeado pelo editor de SPA. Portanto, não precisamos estender explicitamente a interface ComponentExporter como fizemos no capítulo Componente personalizado.

  2. 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.

  3. Abrir CardImpl.java. Esta é a implementação da interface Card.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.

  4. 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ça sling:resourceSuperType do componente Card.

    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 interface Image, sem precisar gravar a lógica. Esta técnica é usada para getSrc(), getAlt() e getTitle().

  5. Em seguida, implemente o método initModel() para iniciar uma variável privada cardPage com base no valor de cardPath

    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.

  6. 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.

  7. 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.
  8. Abra uma janela de terminal e implante apenas as atualizações para o módulo core usando o perfil Maven autoInstallBundle do diretório core.

    code language-shell
    $ cd core/
    $ mvn clean install -PautoInstallBundle
    

    Se estiver usando o AEM 6.x, adicione o perfil classic.

  9. 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.

  1. 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
    
  2. Abrir card.component.ts em ui.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;
    
  3. 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;
        }
        ...
    }
    
  4. 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.
  5. 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
    
  6. Navegue até http://localhost:4502/editor.html/content/wknd-spa-angular/us/en/home.html para ver o componente atualizado:

    Componente de Cartão atualizado no AEM

  7. Você deve ser capaz de recriar o conteúdo existente para criar uma página semelhante ao seguinte:

    Criação Final do Componente de Cartão

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.

recommendation-more-help
e25b6834-e87f-4ff3-ba56-4cd16cdfdec4