Extensión de Core Components en Adobe Experience Manager

A la hora de desarrollar nuevos componentes en AEM, estos pueden realizarse desde cero, o pueden aprovechar algunas de las características de los componentes core de AEM para personalizarlos mínimamente o simplemente usar alguna de sus características y que el resto sea totalmente a medida.

Para poder extender un componente core de AEM vamos a ver cual sería el procedimiento base y diferentes casos de uso que se podrían aplicar a partir de ahí.

Los componentes core no pueden usarse por sí solos directamente en la implementación de AEM para nuestro proyecto. Esto es debido a que de base, en su definición, tienen marcado su grupo como “hidden”, de forma que nunca van a estar disponibles en ninguna plantilla para poder ser insertados en las páginas. Para poder usarlos sin personalización, sino con lo que traen de caja, es necesario como mínimo la generación de un componente proxy, un enlace entre el componente core y nuestro proyecto particular.

Los proyectos arquetipo de AEM ya incluyen componentes proxy para los componentes core, pero en caso de que se necesitará generar un proxy se haría de esta forma.

Primero es necesario generar un componente, con únicamente su archivo .content.xml de especificación:

Ese .content.xml debe incluir un jcr:title para indicar el nombre con el que queremos que aparezca en la interfaz author a la hora de insertarlo en las páginas, un componentGroup que ya esté habilitado en nuestras plantillas para que este componente se pueda insertar en nuestras páginas, y un sling:resourceSuperType apuntando a la ruta origen del componente core para el que estemos generando el componente proxy:

Para ver el catálogo de todos los componentes core existentes y poder consultar las rutas de cada uno, hay que entrar al CRX para consultarlo. En AEM 6.5 estos se encuentran en /apps, en AEM Cloud estos se encuentran en /libs:

Por ejemplo, para cloud, se encuentran en esta ruta: /libs/core/wcm/components

Si por ejemplo queremos en teaser, hay que ir a la versión interna deseada para obtener la ruta para resourceSuperType (recomendable usar la última versión que haya):

Una vez con el componente proxy con únicamente su .content.xml con el contenido indicado, si se despliega en la instancia de AEM, ya podrá usarse en las páginas. Todas sus características (diálogo, funcionalidad, etc.) serán tal cual las del componente core apuntado, sin ningún tipo de personalización.

A partir de este componente proxy, se puede comenzar a hacer personalizaciones sobre él.

La norma básica que aplica AEM a la hora de renderizar este componente es que según va buscando cada elemento que necesita del componente, primero lo busca en el componente extendido en /apps, y si ahí no lo encuentra, lo busca en la ruta referenciada en el resourceSuperType.

De esta forma, como en el componente proxy no hay nada, va a buscar todo a la ruta original del componente core.

Llegados a este punto, vamos a desarrollar cómo se extendería, personalizaría o cambiaría el html del componente. Lo primero que hace falta es obtener el html base del componente original, para llevarlo a nuestro componente extendido y personalizarlo.

Para obtener el original, la forma más sencilla es desde el CRX. Si vamos a la ruta del componente core, veremos dentro de él su html base (y tantos html adicionales como tenga el componente, según cómo se haya desarrollado. Viendo el componente Teaser, tenemos:

Si quisiéramos hacer un cambio únicamente en un html adicional, por ejemplo en el title.html, copiaríamos el contenido directamente en un archivo con el mismo nombre dentro de nuestro componente extendido. Con doble click en el CRX sobre el archivo, tendremos acceso a su contenido para poder copiarlo.

Creando ese archivo en nuestro componente, ya podríamos hacer modificaciones sobre ese html en concreto, de forma que podríamos variar el comportamiento del componente, en ese caso sólo variaríamos el comportamiento en la parte html del título. Si por ejemplo aplicamos este cambio sencillo:

Y lo desplegamos en un entorno, podemos comprobar cómo a la hora de renderizar el html a usado el archivo base del componente core, al no existir un base en el componente extendido, pero el archivo title.html, al existir en el componente extendido, utiliza su contenido en vez del contenido del archivo del componente core:

Si queremos realizar modificaciones sobre el html base, la operativa cambia un poco. No vale con duplicar el archivo base, en este ejemplo teaser.html en el componente extendido, debido a que este componente tiene un nombre diferente (presumiblemente, podría llamarse igual que el del core). Ese archivo base, copiado del mismo modo que el ejemplo anterior, debe ser renombrado para coincidir con el nombre del componente extendido.

Si lo duplicamos de esta forma:

Digital Lover

Es incorrecto, porque al renderizar este componente va a intentar buscar en el componente extendido el archivo base, que se debería llamar “customteaser.html”. Como en este ejemplo eso no existe, va a ir a buscar el html base en el componente core. Como el componente core se llama teaser, el base que busca es teaser.html, ese sí existe en el base, y es el que usaría. Para solucionarlo, hay que renombrar el html base del componente extendido para llamarse como el componente. Esto sí es correcto:

Si por ejemplo realizamos una modificación en este archivo y desplegamos en entorno:

Podemos comprobar cómo lo incluido de ejemplo aparece en pantalla:

Con este sistema ya se podría realizar cualquier tipo de cambio en el html del componente. Si por ejemplo se quiere cambiar toda la estructura del html y dejar de llamar a esos otros archivos html que tenga el componente core (en este caso del teaser hay un title, un image, etc), bastará con eliminar del archivo base extendido las llamadas a esas plantillas. Desde este html base también se llama al Modelo java del componente, en este caso: 

data-sly-use.teaser="com.adobe.cq.wcm.core.components.models.Teaser"

En los cambios que se vayan a realizar sobre el html se puede seguir usando ese modelo sin problema, o se podría combinar con otro nuevo, CustomTeaser por ejemplo que incluyera otros métodos lógicos que se necesitaran sobre esta extensión del componente.

El modelo java se podría sobrescribir con un custom, siempre que se subiera con el mismo paquete, pero esto no es recomendable en absoluto (estropearía cualquier otro intento de extensión de ese componente core en nuestro entorno). En este caso lo más recomendable es utilizar otro modelo a medida propio, e incluir el data-sly-use correspondiente al nuevo modelo, manteniendo también el data-sly-use original si se van a usar métodos del core. También se podría realizar un nuevo modelo java que extendiera el del core, de forma que sólo hubiese un data-sly-use de modelo, apuntando al nuevo, pero que al ser una extensión del original podría tener todos los métodos originales, sobreescritos o no, y cualquier método nuevo que se necesitara. Personalmente no recomiendo esta aproximación, parece mucho más claro y mantenible usar el modelo original para llamadas inalteradas al modelo original, y cualquier cosa que precise algún cambio, implementarla en el nuevo modelo y llamar a él desde el html extendido.

A la hora de extender el componente, uno de los cambios más habituales es la inclusión de nuevos parámetros en el diálogo del componente, de forma que tengamos nuevos datos de entrada, que se modelen en nuevo modelo java y se consuman desde el html extendido como hemos visto. Para extender el diálogo, el procedimiento es similar, pero tiene algunas particularidades propias de cómo se almacena el diálogo en el JCR, ya que no es un archivo como lo es el html.

Si se incluye un diálogo en el componente extendido, no sobrescribe propiamente dicho al diálogo original, sino que lo hace en base al árbol de nodos. Lo que realiza AEM a la hora de pintar el diálogo es un mergeo por nodos entre los del core original y los incluidos en el componente extendido, de forma que si por ejemplo incluimos en el modelo extendido un tab nuevo, con tres campos nuevos, lo que nos encontraremos al ver el diálogo serán los tabs originales acompañados del nuevo tag incluido en el diálogo extendido.

Para poder hacer sobreescrituras, necesitamos que lo que se incluya en el modelo extendido coincida en estructura y nombres de las etiquetas con lo original, en ese caso si prima lo incluido en el componente extendido.

Vamos a ir viéndolo con un ejemplo para saber cómo trabajar. Para obtener el diálogo completo y poder tenerlo en un archivo propio (.content.xml) en nuestro componente extendido, hay varias formas de hacerlo, una de ellas es desde Eclipse utilizando el plugin de AEM. Con este plugin podemos conectarnos a un entorno (preferiblemente local) y realizar subidas de archivos al JCR, y descargas desde el JCR al eclipse, en el formato adecuado para poder desplegar luego esos cambios desde los proyectos.

Para ello, lo primero es desde el CRX copiar los nodos del diálogo a nuestro componente extendido:

Y pegarlo en el componente extendido, guardando después el cambio:

Con el dialog duplicado en el componente extendido, es cuando nos lo podemos descargar a Eclipse con el plugin AEM (y su opción Sling sobre la ruta del componente):

Una vez finalizado el proceso, ya tendremos el diálogo completo del componente core disponible sobre nuestro componente extendido, y podremos hacer modificaciones.

A la hora de modificar, hay que tener en cuenta lo comentado anteriormente, al no ser un archivo, sino un conjunto de nodos, al hacer cambios aquí no pisamos el total de esos nodos, solo los que sobreescribimos aquí con los mismos identificadores.

Por ejemplo, aquí tenemos el tag “actions”, con un título “Links”.

Si cambiáramos ese Title por “Enlaces”, como estamos actuando sobre el nodo llamado “actions”, llamado igual que en el core original, sí vamos a ver ese cambio reflejado tras desplegar:

Ahora bien, si decidimos renombrar el tab entero, y cambiar su contenido (borrando los campos que tiene e incluyendo otros nuevos), por ejemplo:

Nos encontramos con esto al desplegarlo en entorno:

Aparece nuestro Tab nuevo, Botones, pero también aparece el tab original Links. Esto es debido al “mergeo” que realiza AEM, se ha indicado el nuevo tab “actionsCustom”, pero en el componente original sigue existiendo el tab “actions”, con lo que incluye ambos (en el orden que él decide).

Para poder eliminar cosas del original, o las sobreescribimos con los mismos nombres de nodo, o se puede dar orden de ocultar ciertos nodos (y todo lo que tengan por debajo). Siguiendo con el ejemplo, si queremos el nuevo tab “actionsCustom” y eliminar el tab original “actions”, se realiza dando orden de ocultar, incluyendo esta propiedad:

granite:hide="{Boolean}true"

Siguiendo con el ejemplo anterior quedaría:

Desplegando esto:

Conseguimos que el actions original ya no se muestre (se oculta) y sólo se muestra nuestro nodo nuevo actionsCustom con lo que se hubiera incluido en él.

Esto mismo se puede aplicar a campos o a cualquier elemento en la jerarquía de nodos. Si en el tab original actions quisiéramos que no apareciera uno de los campos, pero el resto sí, con mantenerlo y poner la propiedad de ocultación sobre ese campo sería suficiente.

Con todo lo visto anteriormente, ya se podría realizar cualquier tipo de extensión sobre cualquiera de los componentes core de AEM, tanto pequeñas variantes como completos desarrollos a medida que sólo utilizaran alguna característica del componente core original.

 

 

Tags

He leído y acepto la política de privacidad
Acepto recibir emails sobre actividades de recruiting NTT DATA