Render an AEM page and its content and enable authoring on AEM. All child components still need to be mapped to their AEM resourcetypes using MapTo or the components prop. All mapped components also need to be updated to use the newly introduced wrapper EditableComponent.
For default SPA on AEM, the component can be used as-is OOTB.
- ComponentMappingContent is now handled internally, so the usage as illustrated in the sample WKND project as -
export default MapTo('wknd-spa-react/components/page')(
withComponentMappingContext(withRoute(AppPage))
);
can be simplified and now instead be -
export default MapTo('wknd-spa-react/components/page')(
withRoute(AppPage)
);
- Model fetching is now handled internally, so the usage of withModel -
export default withModel(App);
can be removed and can be used simply as -
export default App;
When using the component directly within the app for remote SPA, an additional prop pagePath can be used to pass the path of the corresponding page on AEM.
<Page
pagePath='/content/wknd-app/us/en/home' />
Here, the Page component will render content on the AEM page at us/en/home within the project wknd-app
Render an AEM Layout Container and its content and enable authoring on AEM. Child components to be rendered within the container should be mapped to their AEM resourcetypes using MapTo.
The OOTB ResponsiveGrid component maps to the resourceType wcm/foundation/components/responsivegrid by default.
For default SPA on AEM, the component can be used as-is OOTB.
When using the component directly within the app for remote SPA, two additional props pagePath and itemPath can be used to pass the path of the corresponding content on AEM.
<ResponsiveGrid
pagePath='/content/wknd-app/us/en/home'
itemPath='root/responsivegrid' />
Here,the ResponsiveGrid component will render content of the layout container /content/wknd-app/us/en/home/jcr:content/root/responsivegrid where /content/wknd-app/us/en/home is the page on AEM and root/responsivegrid the path to the item to be rendered within the page.
The ResponsiveGrid component can still be used if content does not exist yet on AEM at the defined path. This will simply add an overlay on AEM for the author when opened for editing in AEM. More details are available in the docs.
If a custom class name needs to be added to the OOTB ResponsiveGrid component, this can be done by passing in the class names as a string via the prop customClassName
<ResponsiveGrid
pagePath='/content/wknd-app/us/en/home'
itemPath='root/responsivegrid'
customClassName='newUserStyleClass' />
For all container components other than ResponsiveGrid, you can either use the Container component as-is or use the helper method getChildComponents() and then render them according to the markup requirements.
Lets say you want to use the WCM Core Container component, and based on user's selection it can either be a ResponsiveGrid or a normal Container.
Here is a sample snippet of how it can be acheived.
const MyContainerEditConfig = {
emptyLabel: 'Container',
isEmpty: function(props){
return !props.cqItemsOrder || !props.cqItemsOrder.length ===0
}
}
const MyContainer = (props) =>
{
const MyComponent = (props.layout!=="SIMPLE")?ResponsiveGrid:Container;
return <MyComponent {...props} />;
}
MapTo('/wknd/components/content/container')(MyContainer, MyContainerEditConfig);
Now lets say you want to render a custom markup for your container, example - a component like Tabs which is also a container, then the sample snippet above can be refactored.
const MyTabsEditConfig = {
emptyLabel: 'Tabs',
isEmpty: function(props){
return !props.cqItemsOrder || !props.cqItemsOrder.length ===0
}
}
const MyTabs = (props) =>
{
const tabItemsInOrder = Container.getChildComponents(props);
const tabItemsJsx = tabItemsInOrder.map((tabItemJsx) =><div className="tab-item">{tabItemJsx}</div>);
return <div className="tabs">{tabItemsJsx}</div>;
}
MapTo('/wknd/components/content/tabs')(MyTabs, MyTabsEditConfig);
Before SPA 2.0, Container component is a class based component an it required the consumers to instantiate the class or use class based inheritance to ontain the child components e.g. this.childComponents in your custom implementation loaded all the child components as an array. Now this needs to be replaced with the helper method as shown in sample snippet above.
<Container
pagePath='/content/wknd-app/us/en/home'
itemPath='root/responsivegrid/container' />
For a custom container, you shall be able to adopt same guidelines followed for normal SPA.
If the model for rendering the component has already been fetched (for eg: in SSR), this can be passed into the component via a prop, so that the component doesn't need to fetch it again on the client side.
const App = ({ model }) => (
<ResponsiveGrid
pagePath='/content/wknd-app/us/en/home'
itemPath='root/responsivegrid'
model={model} />
);
AEM layouting styles are applied by default when using the ResponsiveGrid and Page components. If you would prefer to use your own custom layouting over the AEM authored layouts, an additional prop removeDefaultStyles can be passed into the components.
<ResponsiveGrid
pagePath='/content/wknd-app/us/en/home'
itemPath='root/responsivegrid'
removeDefaultStyles={true} />
This will remove all styles specific to the AEM grid system and corresponsing DOM wrappers.
Mapping child components to a container component can now be done via a prop instead of having to do MapTo on initial load.
If the container components has 2 child components, Text and Image of resource type wknd/text and wknd/image respectively, these can now be mapped to a grid component as below -
<ResponsiveGrid
pagePath='/content/wknd-app/us/en/home'
itemPath='root/responsivegrid'
components={{
"wknd/text": Text,
"wknd/image": Image
}} />
Mapping of the resource type to the corresponding component will then be handled internally by the SPA SDK.
Child components can be lazy loaded to ensure that they are dynamically imported only when needed, thus reducing the amount of code on initial load.
- The container component with the child components to be lazy loaded should be within a Suspense component with fallback content.
- The component to be lazy loaded should be a default export.
To ensure the lazy loaded chunks are imported from the appropriate origin and not the AEM instance when the app is rendered for authoring in the AEM editor, update the SPA to explicitly set the public path to the host URL of the SPA.
import Text from ./components/Text';
MapTo('wknd/text')(Text);
can be updated to lazy load the Text component on usage as below -
MapTo('wknd/text')(React.lazy(() => import('./components/Text')));
<ResponsiveGrid
...
components={{
"wknd/text": Text
}} />
can be updated to lazy load the child components on usage as below -
<ResponsiveGrid
...
components={{
"wknd/text": React.lazy(() => import('./components/Text'))
}} />