Fixed components provide some flexibility for authoring SPA content, however this approach is rigid and requires developers to define the exact composition of the editable content. To support the creation of exceptional experiences by authors, SPA Editor supports the use of container components in the SPA. Container components allow authors to drag and drop allowed components into the container, and author them, just like they can in traditional AEM Sites authoring!
In this chapter, we add an editable container to the home view allowing authors to compose and layout rich content experiences using Editable React components directly in the SPA.
To add a container component to the Home view:
ResponsiveGrid
componentTo add an editable area to the Home view:
Open and edit react-app/src/components/Home.js
Import the ResponsiveGrid
component from @adobe/aem-react-editable-components
and add it to the Home
component.
Set the following attributes on the <ResponsiveGrid...>
component
pagePath = '/content/wknd-app/us/en/home'
itemPath = 'root/responsivegrid'
This instructs the ResponsiveGrid
component to retrieve its content from the AEM resource:
/content/wknd-app/us/en/home/jcr:content/root/responsivegrid
The itemPath
maps to the responsivegrid
node defined in the Remote SPA Page
AEM Template and is automatically created on new AEM Pages created from the Remote SPA Page
AEM Template.
Update Home.js
to add the <ResponsiveGrid...>
component.
...
import { ResponsiveGrid } from '@adobe/aem-react-editable-components';
...
function Home() {
return (
<div className="Home">
<ResponsiveGrid
pagePath='/content/wknd-app/us/en/home'
itemPath='root/responsivegrid'/>
<EditableTitle
pagePath='/content/wknd-app/us/en/home'
itemPath='title'/>
<Adventures />
</div>
);
}
The Home.js
file should look like:
To get the full effect of the flexible authoring experience containers provide in SPA Editor. We’ve already create an editable Title component, but let’s make a few more that allow authors to use editable Text and Image components in the newly added ResponsiveGrid component.
The new editable Text and Image React components are created using the editable component defintion pattern expored in editable fixed components.
Open the SPA project in your IDE
Create a React component at src/components/editable/core/Text.js
Add the following code to Text.js
import React from 'react'
const TextPlain = (props) => <div className={props.baseCssClass}><p className="cmp-text__paragraph">{props.text}</p></div>;
const TextRich = (props) => {
const text = props.text;
const id = (props.id) ? props.id : (props.cqPath ? props.cqPath.substr(props.cqPath.lastIndexOf('/') + 1) : "");
return <div className={props.baseCssClass} id={id} data-rte-editelement dangerouslySetInnerHTML={{ __html: text }} />
};
export const Text = (props) => {
if (!props.baseCssClass) {
props.baseCssClass = 'cmp-text'
}
const { richText = false } = props
return richText ? <TextRich {...props} /> : <TextPlain {...props} />
}
export function textIsEmpty(props) {
return props.text == null || props.text.length === 0;
}
Create an editable React component at src/components/editable/EditableText.js
Add the following code to EditableText.js
import React from 'react'
import { EditableComponent, MapTo } from '@adobe/aem-react-editable-components';
import { Text, textIsEmpty } from "./core/Text";
import { withConditionalPlaceHolder } from "./core/util/withConditionalPlaceholder";
import { withStandardBaseCssClass } from "./core/util/withStandardBaseCssClass";
const RESOURCE_TYPE = "wknd-app/components/text";
const EditConfig = {
emptyLabel: "Text",
isEmpty: textIsEmpty,
resourceType: RESOURCE_TYPE
};
export const WrappedText = (props) => {
const Wrapped = withConditionalPlaceHolder(withStandardBaseCssClass(Text, "cmp-text"), textIsEmpty, "Text V2")
return <Wrapped {...props} />
};
const EditableText = (props) => <EditableComponent config={EditConfig} {...props}><WrappedText /></EditableComponent>
MapTo(RESOURCE_TYPE)(EditableText);
export default EditableText;
The editable Text component implementation should look like:
Open the SPA project in your IDE
Create a React component at src/components/editable/core/Image.js
Add the following code to Image.js
import React from 'react'
import { RoutedLink } from "./RoutedLink";
export const imageIsEmpty = (props) => (!props.src) || props.src.trim().length === 0
const ImageInnerContents = (props) => {
return (<>
<img src={props.src}
className={props.baseCssClass + '__image'}
alt={props.alt} />
{
!!(props.title) && <span className={props.baseCssClass + '__title'} itemProp="caption">{props.title}</span>
}
{
props.displayPopupTitle && (!!props.title) && <meta itemProp="caption" content={props.title} />
}
</>);
};
const ImageContents = (props) => {
if (props.link && props.link.trim().length > 0) {
return (
<RoutedLink className={props.baseCssClass + '__link'} isRouted={props.routed} to={props.link}>
<ImageInnerContents {...props} />
</RoutedLink>
)
}
return <ImageInnerContents {...props} />
};
export const Image = (props) => {
if (!props.baseCssClass) {
props.baseCssClass = 'cmp-image'
}
const { isInEditor = false } = props;
const cssClassName = (isInEditor) ? props.baseCssClass + ' cq-dd-image' : props.baseCssClass;
return (
<div className={cssClassName}>
<ImageContents {...props} />
</div>
)
};
Create an editable React component at src/components/editable/EditableImage.js
Add the following code to EditableImage.js
import { EditableComponent, MapTo } from '@adobe/aem-react-editable-components';
import { Image, imageIsEmpty } from "./core/Image";
import React from 'react'
import { withConditionalPlaceHolder } from "./core/util/withConditionalPlaceholder";
import { withStandardBaseCssClass } from "./core/util/withStandardBaseCssClass";
const RESOURCE_TYPE = "wknd-app/components/image";
const EditConfig = {
emptyLabel: "Image",
isEmpty: imageIsEmpty,
resourceType: RESOURCE_TYPE
};
const WrappedImage = (props) => {
const Wrapped = withConditionalPlaceHolder(withStandardBaseCssClass(Image, "cmp-image"), imageIsEmpty, "Image V2");
return <Wrapped {...props}/>
}
const EditableImage = (props) => <EditableComponent config={EditConfig} {...props}><WrappedImage /></EditableComponent>
MapTo(RESOURCE_TYPE)(EditableImage);
export default EditableImage;
Create an SCSS file src/components/editable/EditableImage.scss
that provides custom styles for the EditableImage.scss
. These styles target the editable React component’s CSS classes.
Add the following SCSS to EditableImage.scss
.cmp-image__image {
margin: 1rem 0;
width: 100%;
border: 0;
}
Import EditableImage.scss
in EditableImage.js
...
import './EditableImage.scss';
...
The editable Image component implementation should look like:
The newly created EditableText
and EditableImage
React components are referenced in the SPA, and are dynamically instantiated based on the JSON returned by AEM. To ensure that these components are available to the SPA, create import statements for them in Home.js
Open the SPA project in your IDE
Open the file src/Home.js
Add import statements for AEMText
and AEMImage
...
// The following need to be imported, so that MapTo is run for the components
import EditableText from './editable/EditableText';
import EditableImage from './editable/EditableImage';
...
The result should look like:
If these imports are not added, the EditableText
and EditableImage
code is not be invoked by SPA, and thus, the components are not mapped to the provided resource types.
AEM container components use policies to dictate their allowed components. This is a critical configuration when using SPA Editor, since only AEM Components that have mapped SPA component counterparts are render-able by the SPA. Ensure only the components which we’ve provided SPA implementations for are allowed:
EditableTitle
mapped to wknd-app/components/title
EditableText
mapped to wknd-app/components/text
EditableImage
mapped to wknd-app/components/image
To configure the Remote SPA Page template’s reponsivegrid container:
Log in to AEM Author
Navigate to Tools > General > Templates > WKND App
Edit Report SPA Page
Select Structure in the mode switcher in the top right
Tap to select the Layout Container
Tap the Policy icon in the popup bar
On the right, under the Allowed Components tab, expand WKND APP - CONTENT
Ensure only following are selected:
Tap Done
After the SPA updated to embed the <ResponsiveGrid...>
, wrappers for three editable React components (EditableTitle
, EditableText
, and EditableImage
), and AEM is updated with a matching Template policy, we can start authoring content in the container component.
Log in to AEM Author
Navigate to Sites > WKND App
Tap Home and select Edit from the top action bar
Select Edit from the mode-selector in the top right of the Page Editor
Locate the Layout Container editable area beneath the Title
Open the Page Editor’s side bar, and select the Components view
Drag the following components into the Layout Container
Drag the components to reorder them to the following order:
Author the Title component
Author the Image component
Author the Text component
Your components are now authored, but stack vertically.
Use AEM’s Layout Mode to allow us to adjust the size and layout of the components.
Switch to Layout Mode using the mode-selector in the top-right
Resize the Image and Text components, such that they are side by side
Preview your changes in AEM Page Editor
Refresh the WKND App running locally on http://localhost:3000 to see the authored changes!
You’ve added a container component that allows for editable components to be added by authors to the WKND App! You now know how to:
ResponsiveGrid
component in the SPAThe next step uses this same technique to add an editable component to an Adventure Details route in the SPA.