Estendere un componente core extend-component
Scopri come estendere un Componente core esistente da utilizzare con l’Editor SPA dell’AEM. Scopri come estendere un componente esistente è una tecnica potente per personalizzare ed espandere le funzionalità di un’implementazione dell’Editor SPA dell’AEM.
Obiettivo
- Estendi un componente core esistente con proprietà e contenuti aggiuntivi.
- Comprendere le nozioni di base dell'ereditarietà dei componenti con l'utilizzo di
sling:resourceSuperType
. - Scopri come sfruttare il Modello di delega per modelli Sling per riutilizzare la logica e le funzionalità esistenti.
Cosa verrà creato
Questo capitolo illustra il codice aggiuntivo necessario per aggiungere una proprietà aggiuntiva a un componente Image
standard per soddisfare i requisiti per un nuovo componente Banner
. Il componente Banner
contiene tutte le stesse proprietà del componente standard Image
, ma include una proprietà aggiuntiva per consentire agli utenti di popolare il Testo banner.
Prerequisiti
Esaminare gli strumenti e le istruzioni necessari per configurare un ambiente di sviluppo locale. A questo punto, si presume che gli utenti abbiano una solida conoscenza della funzione dell’Editor SPA dell’AEM.
Ereditarietà con super tipo di risorsa Sling sling-resource-super-type
Per estendere un componente esistente, impostare una proprietà denominata sling:resourceSuperType
nella definizione del componente. sling:resourceSuperType
è una proprietà che può essere impostata sulla definizione di un componente AEM che punta a un altro componente. In questo modo il componente eredita in modo esplicito tutte le funzionalità del componente identificato come sling:resourceSuperType
.
Se si desidera estendere il componente Image
in wknd-spa-react/components/image
, è necessario aggiornare il codice nel modulo ui.apps
.
-
Crea una nuova cartella sotto il modulo
ui.apps
perbanner
alleui.apps/src/main/content/jcr_root/apps/wknd-spa-react/components/banner
. -
Sotto
banner
creare una definizione di componente (.content.xml
) simile alla seguente: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="Banner" sling:resourceSuperType="wknd-spa-react/components/image" componentGroup="WKND SPA React - Content"/>
In questo modo
wknd-spa-react/components/banner
eredita tutte le funzionalità diwknd-spa-react/components/image
.
cq:editConfig cq-edit-config
Il file _cq_editConfig.xml
determina il comportamento di trascinamento nell'interfaccia utente di creazione AEM. Quando si estende il componente Immagine, è importante che il tipo di risorsa corrisponda al componente stesso.
-
Nel modulo
ui.apps
creare un altro file sottobanner
denominato_cq_editConfig.xml
. -
Popolare
_cq_editConfig.xml
con il seguente 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" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" jcr:primaryType="cq:EditConfig"> <cq:dropTargets jcr:primaryType="nt:unstructured"> <image jcr:primaryType="cq:DropTargetConfig" accept="[image/gif,image/jpeg,image/png,image/webp,image/tiff,image/svg\+xml]" groups="[media]" propertyName="./fileReference"> <parameters jcr:primaryType="nt:unstructured" sling:resourceType="wknd-spa-react/components/banner" imageCrop="" imageMap="" imageRotate=""/> </image> </cq:dropTargets> <cq:inplaceEditing jcr:primaryType="cq:InplaceEditingConfig" active="{Boolean}true" editorType="image"> <inplaceEditingConfig jcr:primaryType="nt:unstructured"> <plugins jcr:primaryType="nt:unstructured"> <crop jcr:primaryType="nt:unstructured" supportedMimeTypes="[image/jpeg,image/png,image/webp,image/tiff]" features="*"> <aspectRatios jcr:primaryType="nt:unstructured"> <wideLandscape jcr:primaryType="nt:unstructured" name="Wide Landscape" ratio="0.6180"/> <landscape jcr:primaryType="nt:unstructured" name="Landscape" ratio="0.8284"/> <square jcr:primaryType="nt:unstructured" name="Square" ratio="1"/> <portrait jcr:primaryType="nt:unstructured" name="Portrait" ratio="1.6180"/> </aspectRatios> </crop> <flip jcr:primaryType="nt:unstructured" supportedMimeTypes="[image/jpeg,image/png,image/webp,image/tiff]" features="-"/> <map jcr:primaryType="nt:unstructured" supportedMimeTypes="[image/jpeg,image/png,image/webp,image/tiff,image/svg+xml]" features="*"/> <rotate jcr:primaryType="nt:unstructured" supportedMimeTypes="[image/jpeg,image/png,image/webp,image/tiff]" features="*"/> <zoom jcr:primaryType="nt:unstructured" supportedMimeTypes="[image/jpeg,image/png,image/webp,image/tiff]" features="*"/> </plugins> <ui jcr:primaryType="nt:unstructured"> <inline jcr:primaryType="nt:unstructured" toolbar="[crop#launch,rotate#right,history#undo,history#redo,fullscreen#fullscreen,control#close,control#finish]"> <replacementToolbars jcr:primaryType="nt:unstructured" crop="[crop#identifier,crop#unlaunch,crop#confirm]"/> </inline> <fullscreen jcr:primaryType="nt:unstructured"> <toolbar jcr:primaryType="nt:unstructured" left="[crop#launchwithratio,rotate#right,flip#horizontal,flip#vertical,zoom#reset100,zoom#popupslider]" right="[history#undo,history#redo,fullscreen#fullscreenexit]"/> <replacementToolbars jcr:primaryType="nt:unstructured"> <crop jcr:primaryType="nt:unstructured" left="[crop#identifier]" right="[crop#unlaunch,crop#confirm]"/> <map jcr:primaryType="nt:unstructured" left="[map#rectangle,map#circle,map#polygon]" right="[map#unlaunch,map#confirm]"/> </replacementToolbars> </fullscreen> </ui> </inplaceEditingConfig> </cq:inplaceEditing> </jcr:root>
-
L'aspetto univoco del file è il nodo
<parameters>
che imposta resourceType suwknd-spa-react/components/banner
.code language-xml <parameters jcr:primaryType="nt:unstructured" sling:resourceType="wknd-spa-react/components/banner" imageCrop="" imageMap="" imageRotate=""/>
La maggior parte dei componenti non richiede
_cq_editConfig
. I componenti immagine e i discendenti sono l’eccezione.
Estendere la finestra di dialogo extend-dialog
Per acquisire il componente Banner
è necessario un campo di testo aggiuntivo nella finestra di dialogo. bannerText
Poiché si utilizza l'ereditarietà Sling, è possibile utilizzare le funzionalità di Sling Resource Merger per ignorare o estendere parti della finestra di dialogo. In questo esempio è stata aggiunta una nuova scheda alla finestra di dialogo per acquisire dati aggiuntivi da un autore per popolare il componente Scheda.
-
Nel modulo
ui.apps
, sotto la cartellabanner
, creare una cartella denominata_cq_dialog
. -
Sotto
_cq_dialog
creare un file di definizione del dialogo.content.xml
. Compila il file con quanto segue:code language-xml <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" jcr:primaryType="nt:unstructured" jcr:title="Banner" sling:resourceType="cq/gui/components/authoring/dialog"> <content jcr:primaryType="nt:unstructured"> <items jcr:primaryType="nt:unstructured"> <tabs jcr:primaryType="nt:unstructured"> <items jcr:primaryType="nt:unstructured"> <text jcr:primaryType="nt:unstructured" jcr:title="Text" sling:orderBefore="asset" sling:resourceType="granite/ui/components/coral/foundation/container" margin="{Boolean}true"> <items jcr:primaryType="nt:unstructured"> <columns jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns" margin="{Boolean}true"> <items jcr:primaryType="nt:unstructured"> <column jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/container"> <items jcr:primaryType="nt:unstructured"> <textGroup granite:hide="${cqDesign.titleHidden}" jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/well"> <items jcr:primaryType="nt:unstructured"> <bannerText jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/textfield" fieldDescription="Text to display on top of the banner." fieldLabel="Banner Text" name="./bannerText"/> </items> </textGroup> </items> </column> </items> </columns> </items> </text> </items> </tabs> </items> </content> </jcr:root>
La definizione XML precedente creerà una nuova scheda denominata Testo e la ordinerà prima della scheda Risorsa esistente. Conterrà un singolo campo Testo banner.
-
La finestra di dialogo si presenterà come segue:
Non è stato necessario definire le schede per Risorsa o Metadati. Questi vengono ereditati tramite la proprietà
sling:resourceSuperType
.Prima di poter visualizzare l'anteprima della finestra di dialogo, è necessario implementare il componente SPA e la funzione
MapTo
.
Implementare il componente SPA implement-spa-component
Per utilizzare il componente Banner con l'editor SPA, è necessario creare un nuovo componente SPA che verrà mappato su wknd-spa-react/components/banner
. Operazione eseguita nel modulo ui.frontend
.
-
Nel modulo
ui.frontend
creare una nuova cartella perBanner
alleui.frontend/src/components/Banner
. -
Creare un nuovo file denominato
Banner.js
sotto la cartellaBanner
. Compila il file con quanto segue:code language-js import React, {Component} from 'react'; import {MapTo} from '@adobe/aem-react-editable-components'; export const BannerEditConfig = { emptyLabel: 'Banner', isEmpty: function(props) { return !props || !props.src || props.src.trim().length < 1; } }; export default class Banner extends Component { get content() { return <img className="Image-src" src={this.props.src} alt={this.props.alt} title={this.props.title ? this.props.title : this.props.alt} />; } // display our custom bannerText property! get bannerText() { if(this.props.bannerText) { return <h4>{this.props.bannerText}</h4>; } return null; } render() { if (BannerEditConfig.isEmpty(this.props)) { return null; } return ( <div className="Banner"> {this.bannerText} <div className="BannerImage">{this.content}</div> </div> ); } } MapTo('wknd-spa-react/components/banner')(Banner, BannerEditConfig);
Questo componente SPA è mappato al componente AEM
wknd-spa-react/components/banner
creato in precedenza. -
Aggiorna
import-components.js
alleui.frontend/src/components/import-components.js
per includere il nuovo componente SPABanner
:code language-diff import './ExperienceFragment/ExperienceFragment'; import './OpenWeather/OpenWeather'; + import './Banner/Banner';
-
A questo punto il progetto può essere implementato all'AEM e il dialogo può essere testato. Distribuisci il progetto utilizzando le abilità Maven:
code language-shell $ cd aem-guides-wknd-spa.react $ mvn clean install -PautoInstallSinglePackage
-
Aggiornare i criteri del modello SPA per aggiungere il componente
Banner
come componente consentito. -
Passare a una pagina SPA e aggiungere il componente
Banner
a una delle pagine SPA:note note NOTE La finestra di dialogo ti consentirà di salvare un valore per Testo banner, ma tale valore non si riflette nel componente SPA. Per abilitare, è necessario estendere il modello Sling per il componente.
Aggiungi interfaccia Java java-interface
Per esporre in definitiva i valori della finestra di dialogo del componente al componente React, è necessario aggiornare il modello Sling che compila il JSON per il componente Banner
. Questa operazione viene eseguita nel modulo core
che contiene tutto il codice Java per il nostro progetto SPA.
Innanzitutto verrà creata una nuova interfaccia Java per Banner
che estende l'interfaccia Java Image
.
-
Nel modulo
core
creare un nuovo file denominatoBannerModel.java
incore/src/main/java/com/adobe/aem/guides/wkndspa/react/core/models
. -
Popolare
BannerModel.java
con quanto segue:code language-java package com.adobe.aem.guides.wkndspa.react.core.models; import com.adobe.cq.wcm.core.components.models.Image; import org.osgi.annotation.versioning.ProviderType; @ProviderType public interface BannerModel extends Image { public String getBannerText(); }
Tutti i metodi verranno ereditati dall'interfaccia del componente core
Image
e verrà aggiunto un nuovo metodogetBannerText()
.
Implementare il modello Sling sling-model
Successivamente, implementare il modello Sling per l'interfaccia BannerModel
.
-
Nel modulo
core
creare un nuovo file denominatoBannerModelImpl.java
incore/src/main/java/com/adobe/aem/guides/wkndspa/react/core/models/impl
. -
Popolare
BannerModelImpl.java
con quanto segue:code language-java package com.adobe.aem.guides.wkndspa.react.core.models.impl; import com.adobe.aem.guides.wkndspa.react.core.models.BannerModel; import com.adobe.cq.export.json.ComponentExporter; import com.adobe.cq.export.json.ExporterConstants; import com.adobe.cq.wcm.core.components.models.Image; import org.apache.sling.models.annotations.*; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.models.annotations.Model; import org.apache.sling.models.annotations.injectorspecific.Self; import org.apache.sling.models.annotations.injectorspecific.ValueMapValue; import org.apache.sling.models.annotations.via.ResourceSuperType; @Model( adaptables = SlingHttpServletRequest.class, adapters = { BannerModel.class,ComponentExporter.class}, resourceType = BannerModelImpl.RESOURCE_TYPE, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL ) @Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION) public class BannerModelImpl implements BannerModel { // points to the the component resource path in ui.apps static final String RESOURCE_TYPE = "wknd-spa-react/components/banner"; @Self private SlingHttpServletRequest request; // With sling inheritance (sling:resourceSuperType) we can adapt the current resource to the Image class // this allows us to re-use all of the functionality of the Image class, without having to implement it ourself // see https://github.com/adobe/aem-core-wcm-components/wiki/Delegation-Pattern-for-Sling-Models @Self @Via(type = ResourceSuperType.class) private Image image; // map the property saved by the dialog to a variable named `bannerText` @ValueMapValue private String bannerText; // public getter to expose the value of `bannerText` via the Sling Model and JSON output @Override public String getBannerText() { return bannerText; } // Re-use the Image class for all other methods: @Override public String getSrc() { return null != image ? image.getSrc() : null; } @Override public String getAlt() { return null != image ? image.getAlt() : null; } @Override public String getTitle() { return null != image ? image.getTitle() : null; } // method required by `ComponentExporter` interface // exposes a JSON property named `:type` with a value of `wknd-spa-react/components/banner` // required to map the JSON export to the SPA component props via the `MapTo` @Override public String getExportedType() { return BannerModelImpl.RESOURCE_TYPE; } }
Osserva l’utilizzo delle annotazioni
@Model
e@Exporter
per garantire che il modello Sling possa essere serializzato come JSON tramite Sling Model Exporter.BannerModelImpl.java
utilizza il pattern di delega per modelli Sling per evitare di riscrivere tutta la logica dal componente di base Immagine. -
Rivedi le righe seguenti:
code language-java @Self @Via(type = ResourceSuperType.class) private Image image;
L'annotazione precedente creerà un'istanza di un oggetto Image denominato
image
in base all'ereditarietàsling:resourceSuperType
del componenteBanner
.code language-java @Override public String getSrc() { return null != image ? image.getSrc() : null; }
È quindi possibile utilizzare semplicemente l'oggetto
image
per implementare i metodi definiti dall'interfacciaImage
, senza dover scrivere direttamente la logica. Questa tecnica è utilizzata pergetSrc()
,getAlt()
egetTitle()
. -
Aprire una finestra del terminale e distribuire solo gli aggiornamenti al modulo
core
utilizzando il profilo MavenautoInstallBundle
dalla directorycore
.code language-shell $ cd core/ $ mvn clean install -PautoInstallBundle
Tutti gli elementi insieme put-together
-
Tornare all'AEM e aprire la pagina SPA contenente il componente
Banner
. -
Aggiorna il componente
Banner
per includere Testo banner: -
Popola il componente con un’immagine:
Salva gli aggiornamenti della finestra di dialogo.
-
Ora dovresti visualizzare il valore renderizzato di Testo banner:
-
Visualizza la risposta del modello JSON in: http://localhost:4502/content/wknd-spa-react/us/en.model.json e cerca
wknd-spa-react/components/card
:code language-json "banner": { "bannerText": "My Banner Text", "src": "/content/wknd-spa-react/us/en/home/_jcr_content/root/responsivegrid/banner.coreimg.jpeg/1622167884688/sport-climbing.jpeg", "alt": "alt banner rock climber", ":type": "wknd-spa-react/components/banner" },
Il modello JSON viene aggiornato con altre coppie chiave/valore dopo l'implementazione del modello Sling in
BannerModelImpl.java
.
Congratulazioni. congratulations
Congratulazioni, hai imparato a estendere un componente AEM utilizzando e come i modelli e le finestre di dialogo Sling funzionano con il modello JSON.