cancel
Showing results for 
Search instead for 
Did you mean: 

How to have custom component implementation for TabParagraphContainerComponent?

0 Kudos

Hi, Everyone.

As explained in this section (customizing-cms-components), the TabParagraphContainerComponent renders a child component coming from CMS. How can we extend it to access multiple child components and render in Spartacus?

In the demo site, we see all the PDP pages have single component assigned to each tab. What if the contents are large needs to included in multiple components as in this Sample Site?

* occ call as show in the above pic

Let's say, the TabParagraphContainerComponent needs to render multiple components in each tabs as in this Sample Site.

Any direction to achieve this scenario would be highly appreciable. Thank you!

Accepted Solutions (0)

Answers (1)

Answers (1)

safin
Advisor
Advisor
0 Kudos

Hi,

My understanding is you want to add more cms components rather than just one cms component for each tab of TabParagraphContainerComponent , is that right?

the main design for default implementation is as follows:

(1) at commerce side, there is a CMS component instance 'TabPanelContainer' which type is of CMSTabParagraphContainer, 'TabPanelContainer' contains four cms component, each one represent one tab.

. ProductDetailsTabComponent, which type is of JspIncludeComponent

. ProductSpecsTabComponent, which type is of JspIncludeComponent

. ProductReviewsTabComponent, which type is of JspIncludeComponent

. deliveryTab, which type is of CMSTabParagraphComponent

(2) 'TabPanelContainer' will be used in the PDP page

(3) the corresponding angular component for CMS component type 'CMSTabParagraphContainer' is TabParagraphContainerComponent at Spartacus side, which is responsible for providing the view of 'TabPanelContainer', it will delegate to specific angular component corresponding to current active tab.

. angular component 'ProductDetailsTabComponent' for cms component 'ProductDetailsTabComponent'

. angular component 'ProductAttributesComponent' for cms component 'ProductSpecsTabComponent'

. angular component 'ProductReviewsComponent' for cms component 'ProductReviewsTabComponent'

. angular component 'ParagraphComponent' for cms component 'deliveryTab'

Here, the key to support multiple cms component for each tab is at Commerce side, it means we need to do something similar like this:

(1) at Commerce side

1.1 introduce new cms component type (for example, CMSContainerComponent), which can contain other cms components as so called children components.

1.2 Create a new cms component instance (suppose the id is myContainerComponent), which type is of CMSContainerComponent, contain other cms components in it

1.3 modify 'TabPanelContainer' to use myContainerComponent to replace the default component where you want to add more cms components for specific tab.

(2) at Spartacus side

2.1 develop new angular component (for example ContainerComponent) to provide the view for CMSContainerComponent

2.2 setup the mapping from angular ContainerComponent to CMSContainerComponent

Hopefully, these comments can help you, 🙂

0 Kudos

Hi, Gang. Appreciate the effort in writing detailed answer.

We have extended TabParagraphContainerComponent component to get children data as Observable and render its markup content in [innerHTML] of angular template. But the problem with this approach is the innerHTML contents will not be compiled by angular CLI and no angular components can be used.

How can we use [cxComponentWrapper] directive to render HTML markup coming from CMS?

children$!: Observable<any[]>[]; components$: Observable<any[]> = this.componentData.data$.pipe( switchMap((data) => combineLatest( data.components!.split(' ').map((component) => this.cmsService.getComponentData<any>(component).pipe( map((tab) => { this.children$ = []; if (tab.children) { tab.children.split(' ').map((comp: string) => { this.children$.push(this.cmsService.getComponentData<any>(comp)); }); } if (!tab.flexType) { tab = { ...tab, flexType: tab.typeCode, }; } return { ...tab, child$: this.children$, title: `CMSTabParagraphContainer.tabs.${tab.uid}`, }; }) ) ) ) ) );
<ng-container *ngFor="let component of components; let i = index"> <div [class.active]="i === activeTabNum" class="dte-tab-content"> <ng-container *ngIf="component.child$.length > 0; else directChildren"> <ng-container *ngFor="let child of component.child$"> <ng-container *ngIf="child | async as childComponent"> <article [innerHTML]="childComponent.content | safeHtml"></article> </ng-container> </ng-container> </ng-container> <ng-template #directChildren> <ng-template [cxComponentWrapper]="component"></ng-template> </ng-template> </div></ng-container>