I had the following data model in backend:
AccordionComponentContainer extends CMSTabParagraphContainer
AccordionItemComponent extends SimpleCMSComponent
The container extending the CMSTabParagraphContainer because extending the AbstractCMSComponentContainer is pain in the ass (generated jalo classes has to be adapted but this isn't important for this case, only for understanding.
Now I have a component in Spartacus CmsAccordionComponent. I introduced a component mapping:
AccordionComponentContainer: {
component: CmsAccordionComponent,
},
In my component html file I have something like this:
<h2>{{headline$ | async}}</h2>
<ul>
<ng-container *ngFor="let component of components$ | async; let i = index">
<li>{{component.content}}</li>
</ng-container>
</ul>
I used the files in
projects/storefrontlib/src/cms-components/content/tab-paragraph-container
as
reference for my implementation (e.g. component implementation). Expect of ng-template (cxOutlet):
<ng-template [cxOutlet]="component.flexType" [cxOutletContext]="{}">
<ng-container [cxComponentWrapper]="component"></ng-container>
</ng-template>
Before, I tried the same solution as CMSTabParagraphContainer. For some reason this won't work in my project. I introduced an own component and a mapping for the children (AccordionItemComponent) but it didn't work. The child components aren't shown.
So I used my solution described above. With my solution the components are displayed (also the child components) but I cannot edit them in SmartEdit. Maybe it's related with this issue: https://github.com/SAP/spartacus/issues/1484.
For testing purpose I added the 'normal' CMSTabParagraphContainer with CMSParagraphComponent's to my content slot in the backoffice. And I can edit the first CMSParagraphComponent that is shown in SmartEdit. Unfortunately I cannot add new paragraphs to the CMSTabParagraphContainer. Therefore I think that the ng-template (cxOutlet) solution is the better one as mine.
Can you please explain how the TabParagraphContainerComponent and the snippet ng-template (cxOutlet) works? Also I think that this should considered in the github issue ticket (https://github.com/SAP/spartacus/issues/1484) so that CMSTabParagraphContainer (AbstractCMSComponentContainer) are better supported in Spartacus (SmartEdit).
Thanks for your help!
The most important piece is the cxComponentWrapper
. This directive takes the component slot data and renders the component inside.
The cxComponentWrapper
requires the following data set for each component:
{
flexType: item.typeCode,
typeCode: item.typeCode,
uid: item?.uid
}
A typical container component template implementation would iterate over the various components and applies the directive:
<ng-container *ngFor="let item of items$ | async">
<ng-container
[cxComponentWrapper]="{
flexType: item.typeCode,
typeCode: item.typeCode,
uid: item?.uid
}"
>
</ng-container>
</ng-container>
The problem that you'll likely face, is the lack of the component type
in the container component cms data. The cms api will only expose the component UIDs for the various nested components. You need to fetch the component type from the backend, using CmsService.getComponentData
. You need to do this for each component uid. If you do this in a loop, Spartacus will actually merge the various calls to CmsService.getComponentData and do a single call to the backend.
An example of such an implementation can be found at https://github.com/SAP/spartacus/blob/746a15c1b63998065b0ceea96f4da052829533fb/projects/storefrontlib/src/cms-components/content/banner-carousel/banner-carousel.component.ts#L25.