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.
sling:resourceSuperType
.Questo capitolo illustra il codice aggiuntivo necessario per aggiungere una proprietà aggiuntiva a uno standard Image
componente per soddisfare i requisiti per un nuovo Banner
componente. Il Banner
il componente contiene tutte le stesse proprietà dello standard Image
ma include una proprietà aggiuntiva che consente agli utenti di compilare il Testo banner.
Esaminare gli strumenti e le istruzioni necessari per l'impostazione di un ambiente di sviluppo locale. A questo punto, si presume che gli utenti abbiano una solida conoscenza della funzione dell’Editor SPA dell’AEM.
Per estendere un componente esistente, imposta una proprietà denominata sling:resourceSuperType
nella definizione del componente. sling:resourceSuperType
è un proprietà che può essere impostata sulla definizione di un componente AEM che punta a un altro componente. Questo imposta esplicitamente il componente in modo che erediti tutte le funzionalità del componente identificato come sling:resourceSuperType
.
Se si desidera estendere Image
componente in wknd-spa-react/components/image
è necessario aggiornare il codice in ui.apps
modulo.
Crea una nuova cartella sotto il ui.apps
modulo per banner
a ui.apps/src/main/content/jcr_root/apps/wknd-spa-react/components/banner
.
Sotto banner
creare una definizione di componente (.content.xml
) come segue:
<?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"/>
Questo set wknd-spa-react/components/banner
per ereditare tutte le funzionalità di wknd-spa-react/components/image
.
Il _cq_editConfig.xml
file determina il comportamento di trascinamento nell’interfaccia utente di creazione dell’AEM. Quando si estende il componente Immagine, è importante che il tipo di risorsa corrisponda al componente stesso.
In ui.apps
modulo crea un altro file sotto banner
denominato _cq_editConfig.xml
.
Popolare _cq_editConfig.xml
con il seguente 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 è <parameters>
nodo che imposta resourceType su wknd-spa-react/components/banner
.
<parameters
jcr:primaryType="nt:unstructured"
sling:resourceType="wknd-spa-react/components/banner"
imageCrop=""
imageMap=""
imageRotate=""/>
La maggior parte dei componenti non richiede un _cq_editConfig
. I componenti immagine e i discendenti sono l’eccezione.
Nostro Banner
il componente richiede un campo di testo aggiuntivo nella finestra di dialogo per acquisire bannerText
. Poiché utilizziamo l’ereditarietà Sling, possiamo utilizzare le funzioni di Sling Resource Merger per sostituire 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.
In ui.apps
modulo, sotto banner
cartella, crea una cartella denominata _cq_dialog
.
Sotto _cq_dialog
creare un file di definizione del dialogo .content.xml
. Compila il file con quanto segue:
<?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 ordinarlo prima di esistente Risorsa scheda. Conterrà un singolo campo Testo banner.
La finestra di dialogo si presenterà come segue:
Non era necessario definire le schede per Risorsa o Metadati. Questi vengono ereditati tramite sling:resourceSuperType
proprietà.
Prima di poter visualizzare l’anteprima del dialogo, è necessario implementare la componente SPA e la MapTo
funzione.
Per utilizzare il componente Banner con l’editor SPA, è necessario creare un nuovo componente SPA che verrà mappato su wknd-spa-react/components/banner
. Questa operazione viene eseguita nel ui.frontend
modulo.
In ui.frontend
modulo crea una nuova cartella per Banner
a ui.frontend/src/components/Banner
.
Crea un nuovo file denominato Banner.js
sotto Banner
cartella. Compila il file con quanto segue:
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);
Questa componente SPA è mappata sulla componente AEM wknd-spa-react/components/banner
creato in precedenza.
Aggiorna import-components.js
a ui.frontend/src/components/import-components.js
per includere il nuovo Banner
Componente SPA:
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:
$ cd aem-guides-wknd-spa.react
$ mvn clean install -PautoInstallSinglePackage
Aggiorna i criteri del modello SPA per aggiungere il Banner
componente come componente consentito.
Passa a una pagina SPA e aggiungi Banner
componente in una delle pagine dell’SPA:
La finestra di dialogo ti consente di salvare un valore per Testo banner ma questo valore non si riflette nella componente SPA. Per abilitare, è necessario estendere il modello Sling per il componente.
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 Banner
componente. Questa operazione viene eseguita nel core
che contiene tutto il codice Java per il nostro progetto SPA.
Innanzitutto verrà creata una nuova interfaccia Java per Banner
che estende Image
Interfaccia Java.
In core
modulo crea un nuovo file denominato BannerModel.java
a core/src/main/java/com/adobe/aem/guides/wkndspa/react/core/models
.
Popolare BannerModel.java
con le seguenti caratteristiche:
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();
}
Questo erediterà tutti i metodi dal componente core Image
e aggiungere un nuovo metodo getBannerText()
.
Ora, implementa il modello Sling per BannerModel
di rete.
In core
modulo crea un nuovo file denominato BannerModelImpl.java
a core/src/main/java/com/adobe/aem/guides/wkndspa/react/core/models/impl
.
Popolare BannerModelImpl.java
con le seguenti caratteristiche:
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 di @Model
e @Exporter
annotazioni per garantire che il modello Sling possa essere serializzato come JSON tramite Sling Model Exporter.
BannerModelImpl.java
utilizza Pattern di delega per modelli Sling per evitare di riscrivere tutta la logica dal componente core Immagine.
Rivedi le righe seguenti:
@Self
@Via(type = ResourceSuperType.class)
private Image image;
L’annotazione precedente crea un’istanza di un oggetto Image denominato image
in base al sling:resourceSuperType
ereditarietà del Banner
componente.
@Override
public String getSrc() {
return null != image ? image.getSrc() : null;
}
È quindi possibile utilizzare semplicemente il image
oggetto per implementare i metodi definiti dal Image
senza dover scrivere direttamente la logica. Questa tecnica viene utilizzata per getSrc()
, getAlt()
e getTitle()
.
Apri una finestra del terminale e distribuisci solo gli aggiornamenti a core
modulo di utilizzando Maven autoInstallBundle
profilo da core
directory.
$ cd core/
$ mvn clean install -PautoInstallBundle
Torna all’AEM e apri la pagina dell’SPA che presenta Banner
componente.
Aggiornare il Banner
componente da includere Testo banner:
Popola il componente con un’immagine:
Salva gli aggiornamenti della finestra di dialogo.
Ora dovresti vedere 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 il wknd-spa-react/components/card
:
"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"
},
Nota che il modello JSON viene aggiornato con altre coppie chiave/valore dopo l’implementazione del modello Sling in BannerModelImpl.java
.
Congratulazioni, hai imparato a estendere un componente AEM utilizzando e come i modelli e le finestre di dialogo Sling funzionano con il modello JSON.