Ampliación de un componente principal extend-component
AEM SPA Obtenga información sobre cómo ampliar un componente principal existente para utilizarlo con el Editor de. AEM SPA Comprender cómo ampliar un componente existente es una técnica potente para personalizar y ampliar las capacidades de una implementación de Editor de de trabajo.
Objetivo
- Ampliar un componente principal existente con propiedades y contenido adicionales.
- Comprenda los conceptos básicos de la herencia de componentes con el uso de
sling:resourceSuperType
. - Aprenda a aprovechar Patrón de delegación para modelos Sling para reutilizar la lógica y la funcionalidad existentes.
Qué va a generar
Este capítulo ilustra el código adicional necesario para agregar una propiedad adicional a un componente estándar Image
para cumplir los requisitos de un nuevo componente Banner
. El componente Banner
contiene las mismas propiedades que el componente Image
estándar, pero incluye una propiedad adicional para que los usuarios rellenen Banner Text.
Requisitos previos
Revise las herramientas y las instrucciones necesarias para configurar un entorno de desarrollo local. AEM SPA En este punto del tutorial se da por hecho que los usuarios tienen una comprensión sólida de la función de editor de contenido (Editor de contenido) de la.
Herencia con el supertipo de recursos de Sling sling-resource-super-type
Para ampliar un componente existente, establezca una propiedad denominada sling:resourceSuperType
en la definición del componente. AEM sling:resourceSuperType
es una propiedad que se puede establecer en la definición de un componente de un componente de la red que señala a otro componente. Esto establece explícitamente que el componente heredará toda la funcionalidad del componente identificado como sling:resourceSuperType
.
Si queremos extender el componente Image
en wknd-spa-react/components/image
, necesitamos actualizar el código en el módulo ui.apps
.
-
Cree una nueva carpeta debajo del módulo
ui.apps
parabanner
enui.apps/src/main/content/jcr_root/apps/wknd-spa-react/components/banner
. -
Debajo de
banner
, cree una definición de componente (.content.xml
) como la siguiente: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"/>
Esto configura
wknd-spa-react/components/banner
para que herede toda la funcionalidad dewknd-spa-react/components/image
.
cq:editConfig cq-edit-config
AEM El archivo _cq_editConfig.xml
dicta el comportamiento de arrastrar y soltar en la interfaz de usuario de creación de. Al ampliar el componente de imagen, es importante que el tipo de recurso coincida con el propio componente.
-
En el módulo
ui.apps
, cree otro archivo debajo debanner
con el nombre_cq_editConfig.xml
. -
Rellene
_cq_editConfig.xml
con el siguiente 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>
-
El aspecto único del archivo es el nodo
<parameters>
que establece resourceType enwknd-spa-react/components/banner
.code language-xml <parameters jcr:primaryType="nt:unstructured" sling:resourceType="wknd-spa-react/components/banner" imageCrop="" imageMap="" imageRotate=""/>
La mayoría de los componentes no requieren un
_cq_editConfig
. Los componentes de imagen y los descendientes son la excepción.
Ampliación del cuadro de diálogo extend-dialog
Nuestro componente Banner
requiere un campo de texto adicional en el cuadro de diálogo para capturar bannerText
. Como estamos usando la herencia de Sling, podemos usar las características de Fusión de recursos de Sling para anular o ampliar partes del cuadro de diálogo. En este ejemplo, se ha añadido una nueva pestaña al cuadro de diálogo para capturar datos adicionales de un autor para rellenar el componente de tarjeta.
-
En el módulo
ui.apps
, debajo de la carpetabanner
, cree una carpeta denominada_cq_dialog
. -
Debajo de
_cq_dialog
cree un archivo de definición de cuadro de diálogo.content.xml
. Rellénelo con lo siguiente: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 definición XML anterior creará una nueva ficha denominada Texto y la ordenará antes de la ficha Recurso existente. Contendrá un solo campo Texto del titular.
-
El cuadro de diálogo tendrá el siguiente aspecto:
Observe que no tuvimos que definir las fichas para Asset o Metadata. Se heredan mediante la propiedad
sling:resourceSuperType
.SPA Antes de poder obtener una vista previa del cuadro de diálogo, es necesario implementar el Componente de y la función
MapTo
.
SPA Implementar componente de implement-spa-component
SPA SPA Para usar el componente Banner con el Editor de, se debe crear un nuevo componente de la que se asignará a wknd-spa-react/components/banner
. Esto se hace en el módulo ui.frontend
.
-
En el módulo
ui.frontend
, cree una nueva carpeta paraBanner
enui.frontend/src/components/Banner
. -
Cree un nuevo archivo con el nombre
Banner.js
debajo de la carpetaBanner
. Rellénelo con lo siguiente: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);
SPA AEM Este componente se asigna al componente de
wknd-spa-react/components/banner
creado anteriormente. -
SPA Actualice
import-components.js
a lasui.frontend/src/components/import-components.js
para incluir el nuevo componente de la aplicaciónBanner
de la:code language-diff import './ExperienceFragment/ExperienceFragment'; import './OpenWeather/OpenWeather'; + import './Banner/Banner';
-
AEM En este punto, el proyecto se puede implementar para que se ejecute y el cuadro de diálogo se pueda probar. Implemente el proyecto con sus habilidades con Maven:
code language-shell $ cd aem-guides-wknd-spa.react $ mvn clean install -PautoInstallSinglePackage
-
SPA Actualice la directiva de la plantilla de la plantilla de la plantilla de datos para agregar el componente
Banner
como un componente permitido. -
SPA SPA Vaya a una página de la y agregue el componente
Banner
a una de las páginas de la:note note NOTE SPA El cuadro de diálogo le permitirá guardar un valor para Texto del titular, pero este valor no se refleja en el componente de la. Para habilitarlo, necesitamos extender el modelo Sling para el componente.
Añadir interfaz de Java java-interface
Para exponer finalmente los valores del cuadro de diálogo del componente al componente React, debemos actualizar el modelo Sling que rellena el JSON para el componente Banner
. SPA Esto se hace en el módulo core
que contiene todo el código Java para nuestro proyecto de.
En primer lugar, crearemos una nueva interfaz Java para Banner
que amplía la interfaz Java Image
.
-
En el módulo
core
, cree un nuevo archivo con el nombreBannerModel.java
encore/src/main/java/com/adobe/aem/guides/wkndspa/react/core/models
. -
Rellene
BannerModel.java
con lo siguiente: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(); }
Esto heredará todos los métodos de la interfaz del componente principal
Image
y agregará un nuevo métodogetBannerText()
.
Implementar el modelo Sling sling-model
A continuación, implemente el modelo Sling para la interfaz BannerModel
.
-
En el módulo
core
, cree un nuevo archivo con el nombreBannerModelImpl.java
encore/src/main/java/com/adobe/aem/guides/wkndspa/react/core/models/impl
. -
Rellene
BannerModelImpl.java
con lo siguiente: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; } }
Observe el uso de las anotaciones
@Model
y@Exporter
para asegurarse de que el modelo Sling se pueda serializar como JSON a través del exportador del modelo Sling.BannerModelImpl.java
utiliza el patrón de delegación para modelos Sling para evitar que se vuelva a escribir toda la lógica desde el componente principal de imagen. -
Revise las líneas siguientes:
code language-java @Self @Via(type = ResourceSuperType.class) private Image image;
La anotación anterior creará una instancia de un objeto de imagen denominado
image
basado en la herenciasling:resourceSuperType
del componenteBanner
.code language-java @Override public String getSrc() { return null != image ? image.getSrc() : null; }
Entonces, es posible usar simplemente el objeto
image
para implementar métodos definidos por la interfazImage
, sin tener que escribir la lógica nosotros mismos. Esta técnica se usa paragetSrc()
,getAlt()
ygetTitle()
. -
Abra una ventana de terminal e implemente solo las actualizaciones del módulo
core
mediante el perfil MavenautoInstallBundle
desde el directoriocore
.code language-shell $ cd core/ $ mvn clean install -PautoInstallBundle
En resumen put-together
-
AEM SPA Vuelva a la página de inicio y abra la página de la aplicación que tiene el componente
Banner
. -
Actualizar el componente
Banner
para incluir Texto del titular: -
Rellene el componente con una imagen:
Guarde las actualizaciones del cuadro de diálogo.
-
Ahora debería ver el valor procesado de Texto del titular:
-
Vea la respuesta del modelo JSON en: http://localhost:4502/content/wknd-spa-react/us/en.model.json y busque
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" },
Observe que el modelo JSON se actualiza con pares clave/valor adicionales después de implementar el modelo Sling en
BannerModelImpl.java
.
Enhorabuena. congratulations
AEM ¡Enhorabuena! Ha aprendido a ampliar un componente de mediante y cómo funcionan los modelos Sling y los cuadros de diálogo con el modelo JSON.