Goal
Refresh & Render the SPA component with updated model data when a user adds new content in dialog...
Demo | Package Install | Github
Solution
1) Updating the component is a 2 step process...
a) Trigger a custom event from the SPA editor with latest dialog data...
b) Listen to the event in component render script and update...
Trigger Custom Event
1) Add a client library to extend editable action EditableActions.REFRESH and pass the updated model in a custom event eaem-spa-component-refresh-event. Login to CRXDE Lite (http://localhost:4502/crx/de), create folder /apps/eaem-sites-spa-how-to-react/clientlibs
2) Create node /apps/eaem-sites-spa-how-to-react/clientlibs/clientlib-extensions of type cq:ClientLibraryFolder, add String[] property categories with value [cq.authoring.editor], String[] property dependencies with value lodash.
3) Create file (nt:file) /apps/eaem-sites-spa-how-to-react/clientlibs/clientlib-extensions/js.txt, add
refresh-component.js
4) Create file (nt:file) /apps/eaem-sites-spa-how-to-react/clientlibs/clientlib-extensions/refresh-component.js, add the following code
(function($, $document){
var EAEM_COMPONENTS = "eaem-sites-spa-how-to-react/",
EAEM_SPA_COMP_REFRESH_EVENT = "eaem-spa-component-refresh-event";
$document.on("cq-editables-loaded", overrideSPAImageCompRefresh);
function overrideSPAImageCompRefresh(){
var _origExec = Granite.author.edit.EditableActions.REFRESH.execute;
Granite.author.edit.EditableActions.REFRESH.execute = function(editable, config){
if(editable.type.startsWith(EAEM_COMPONENTS)){
$.ajax(editable.slingPath).done(function(compData){
sendComponentRefreshEvent(editable, compData);
});
}
return _origExec.call(this, editable, config);
};
}
function sendComponentRefreshEvent(editable, compData){
let event = new CustomEvent(EAEM_SPA_COMP_REFRESH_EVENT, {
detail: {
type: editable.type,
path: editable.path,
slingPath: editable.slingPath,
data: compData
}
});
window.dispatchEvent(event);
}
}(jQuery, jQuery(document)));
import { MapTo } from '@adobe/cq-react-editable-components';
import DOMPurify from 'dompurify';
import React, { Component } from 'react';
import {Link} from "react-router-dom";
const ImageEditConfig = {
emptyLabel: 'Image - Experience AEM',
isEmpty: function (props) {
return (!props || !props.fileReference || (props.fileReference.trim().length < 1));
}
};
class Image extends Component {
componentDidMount() {
//todo check for wcmmode
window.parent.addEventListener("eaem-spa-component-refresh-event", (event => {
if( !event.detail || (event.detail.type !== this.props.cqType)){
return;
}
Object.assign(this.props, event.detail.data);
this.forceUpdate();
}).bind(this));
}
get imageHTML() {
const imgStyles = {
"display": 'block',
"margin-left": 'auto',
"margin-right": 'auto'
};
return (
<div>
<Link to={this.props.imageLink}>
<img src={this.props.fileReference} style={imgStyles}/>
</Link>
</div>
);
}
render() {
return this.imageHTML;
}
}
export default MapTo('eaem-sites-spa-how-to-react/components/image')(Image,ImageEditConfig);