Expand my Community achievements bar.

SOLVED

Custom Table Component

Avatar

Level 1

Hi, 

 

I'm trying to build a table component from scratch as the existing OOTB table is deprecated for  AEM 6.5. 

I wanted to include a component inside a table cell and should be able to edit it. For example, I want to include an image component in the last column of the table, I should be able to add it via dialog and edit it in page.

 

I got to know that it is not possible with the existing Core Text component table structure as RTE plugins would not allow adding a component inside a cell except text input. 

 

So, I tried to add custom dialog with multifield inputs and output the table as below.

 

<table width="100%" cellspacing="0" cellpadding="1" border="1">
<!--/* Get all child resources */-->
<div data-sly-list.rowsMultifield="${resource.getChildren}">
    <div data-sly-test="${rowsMultifield.name == 'rows'}">
        <ul data-sly-list.rows="${rowsMultifield.getChildren}">
                <tr>
                    <!--/* Get all child resources */-->
                    <div data-sly-list.cellMultifield="${rows.getChildren}">

                        <!--/* Keep only the countries multifield and iterate over its children */-->
                        <ul data-sly-test="${cellMultifield.name == 'cells'}"
                            data-sly-list.cell="${cellMultifield.getChildren}">


							<div data-sly-test="${properties.headerRow && (rowsList.index == 0)}">

                                <th>
                                    <sly data-sly-resource="${ 'rows/{0}/cells/{1}/*' @ format=[rows.name,cell.name], resourceType='macnicagwi/components/content/text', decorationTagName='div', cssClassName='header-row'}">
                                    </sly>
                                </th>

							</div>

							<div data-sly-test="${properties.headerRow && (rowsList.index != 0) }">

                                <th data-sly-test="${properties.headerColumn && (cellList.index == 0)}">
                                    <sly data-sly-resource="${ 'rows/{0}/cells/{1}/*' @ format=[rows.name,cell.name], resourceType='macnicagwi/components/content/text', decorationTagName='div', cssClassName='header-column'}">
                                    </sly>
                                </th>

                                <td data-sly-test="${properties.headerColumn && (cellList.index != 0)}">
                                    <sly data-sly-resource="${ 'rows/{0}/cells/{1}/*' @ format=[rows.name,cell.name], resourceType=cell.type, decorationTagName='div'}">
                                    </sly>
                                </td>

								<td data-sly-test="${!properties.headerColumn}">
                                    <sly data-sly-resource="${ 'rows/{0}/cells/{1}/*' @ format=[rows.name,cell.name], resourceType=cell.type, decorationTagName='div'}">
                                    </sly>
                            	</td>
							</div>



							<div data-sly-test="${!properties.headerRow}">

                                <th data-sly-test="${properties.headerColumn && (cellList.index == 0)}">
                                    <sly data-sly-resource="${ 'rows/{0}/cells/{1}/*' @ format=[rows.name,cell.name], resourceType='macnicagwi/components/content/text', decorationTagName='div', cssClassName='header-column'}">
                                    </sly>
                                </th>
    
    
                                <td data-sly-test="${properties.headerColumn && (cellList.index != 0)}">
                                    <sly data-sly-resource="${ 'rows/{0}/cells/{1}/*' @ format=[rows.name,cell.name], resourceType=cell.type, decorationTagName='div'}">
                                    </sly>
                                </td>
    
    
                                <td data-sly-test="${!properties.headerColumn}">
                                    <sly data-sly-resource="${ 'rows/{0}/cells/{1}/*' @ format=[rows.name,cell.name], resourceType=cell.type, decorationTagName='div'}">
                                    </sly>
                                </td>

							</div>
                        
                        </ul>
                    </div>
                </tr>
        </ul>
    </div>
</div>
</table>

And this is the dialog

vijay_karthik_0-1650462430127.png

So, the problem is everytime I add a new multifield and click on done, the entire table data is getting refactored to the beginning. All the edited data is getting lost. 

 

vijay_karthik_1-1650462548999.png

How do I retain the data in case if I add a new row or a cell?

OR, in short,  how to add a component in a table cell ?@

 

 

1 Accepted Solution

Avatar

Correct answer by
Employee Advisor

Hi @vijay_karthik ,

 

Here is a tutorial to have a table component and also customising it in AEM :
https://www.youtube.com/watch?v=RRqovsPq5Lo

Please refer the same, let us know if you have any further concerns.

Thanks.

View solution in original post

6 Replies

Avatar

Correct answer by
Employee Advisor

Hi @vijay_karthik ,

 

Here is a tutorial to have a table component and also customising it in AEM :
https://www.youtube.com/watch?v=RRqovsPq5Lo

Please refer the same, let us know if you have any further concerns.

Thanks.

Avatar

Level 1
Level 1

<!-- /apps/your-project/components/custom-table/custom-table.html -->
<div class="custom-table">
<table>
<thead>
<tr>
<!-- Generate table headers -->
<sly data-sly-use.table="com.example.CustomTable">
<sly data-sly-repeat.header="${table.getHeaders()}">
<th>${header}</th>
</sly>
</sly>
</tr>
</thead>
<tbody>
<!-- Generate table rows and columns based on the provided data -->
<sly data-sly-use.table="com.example.CustomTable">
<sly data-sly-repeat.row="${table.getRows()}">
<tr>
<sly data-sly-repeat.col="${table.getColumns()}">
<td>Row ${row.index + 1}, Col ${col.index + 1}</td>
</sly>
</tr>
</sly>
</sly>
</tbody>
</table>
</div>

Avatar

Level 1
Level 1

custom-table
└── cq:dialog
├── content
│ └── items
│ └── root
│ ├── jcr:primaryType: nt:unstructured
│ ├── sling:resourceType: cq/gui/components/authoring/dialog
│ └── items
│ └── tab1
│ ├── jcr:primaryType: nt:unstructured
│ ├── sling:resourceType: cq/gui/components/authoring/dialog/tab
│ ├── title: Table Properties
│ └── items
│ └── columns
│ ├── jcr:primaryType: nt:unstructured
│ ├── sling:resourceType: cq/gui/components/authoring/dialog/column
│ ├── items
│ │ └── column
│ │ ├── jcr:primaryType: nt:unstructured
│ │ ├── sling:resourceType: cq/gui/components/authoring/dialog/fieldset
│ │ ├── items
│ │ │ ├── rows
│ │ │ │ ├── jcr:primaryType: nt:unstructured
│ │ │ │ ├── sling:resourceType: cq/gui/components/authoring/dialog/numberfield
│ │ │ │ ├── fieldLabel: Rows
│ │ │ │ ├── name: ./rows
│ │ │ │ ├── allowBlank: false
│ │ │ │ ├── minValue: 1
│ │ │ │ └── xtype: numberfield
│ │ │ ├── columns
│ │ │ │ ├── jcr:primaryType: nt:unstructured
│ │ │ │ ├── sling:resourceType: cq/gui/components/authoring/dialog/numberfield
│ │ │ │ ├── fieldLabel: Columns
│ │ │ │ ├── name: ./columns
│ │ │ │ ├── allowBlank: false
│ │ │ │ ├── minValue: 1
│ │ │ │ └── xtype: numberfield
│ │ │ ├── tableHeaders
│ │ │ │ ├── jcr:primaryType: nt:unstructured
│ │ │ │ ├── sling:resourceType: cq/gui/components/authoring/dialog/multifield
│ │ │ │ ├── fieldLabel: Table Headers
│ │ │ │ └── field
│ │ │ │ ├── jcr:primaryType: nt:unstructured
│ │ │ │ ├── sling:resourceType: cq/gui/components/authoring/dialog/textfield
│ │ │ │ ├── name: ./headers
│ │ │ │ └── allowBlank: false
│ │ └── jcr:primaryType: nt:unstructured
│ └── jcr:primaryType: nt:unstructured
└── jcr:primaryType: nt:unstructured


Java code:
======

package com.example;

import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;

import java.util.List;

@Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class CustomTable {

@Self
private Resource resource;

@ValueMapValue
private int rows;

@ValueMapValue
private int columns;

@ValueMapValue
private List<String> headers;

public int getRows() {
return rows;
}

public int getColumns() {
return columns;
}

public List<String> getHeaders() {
return headers;
}
}






Avatar

Level 1
Level 1

<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:Dialog"
cq:dialogType="floating">
<content jcr:primaryType="nt:unstructured" sling:resourceType="cq/gui/components/authoring/dialog">
<items jcr:primaryType="nt:unstructured">
<root jcr:primaryType="nt:unstructured">
<items jcr:primaryType="nt:unstructured">
<tab1 jcr:primaryType="nt:unstructured" sling:resourceType="cq/gui/components/authoring/dialog/tab" title="Table Properties">
<items jcr:primaryType="nt:unstructured">
<columns jcr:primaryType="nt:unstructured" sling:resourceType="cq/gui/components/authoring/dialog/column">
<items jcr:primaryType="nt:unstructured">
<column jcr:primaryType="nt:unstructured" sling:resourceType="cq/gui/components/authoring/dialog/fieldset">
<items jcr:primaryType="nt:unstructured">
<rows jcr:primaryType="nt:unstructured" sling:resourceType="cq/gui/components/authoring/dialog/numberfield"
fieldLabel="Rows"
name="./rows"
allowBlank="{Boolean}false"
minValue="{Long}1"
xtype="numberfield"/>
<columns jcr:primaryType="nt:unstructured" sling:resourceType="cq/gui/components/authoring/dialog/numberfield"
fieldLabel="Columns"
name="./columns"
allowBlank="{Boolean}false"
minValue="{Long}1"
xtype="numberfield"/>
<tableHeaders jcr:primaryType="nt:unstructured" sling:resourceType="cq/gui/components/authoring/dialog/multifield"
fieldLabel="Table Headers">
<field jcr:primaryType="nt:unstructured" sling:resourceType="cq/gui/components/authoring/dialog/textfield"
name="./headers"
allowBlank="{Boolean}false"/>
</tableHeaders>
</items>
</column>
</items>
</columns>
</items>
</tab1>
</items>
</root>
</items>
</content>
</jcr:root>

Avatar

Level 1
Level 1

<table>
<thead>
<tr class="header-content-row">
<td class="blank-cell"></td>
<td class="table-spacer-column"></td>
<sly data-sly-list.header="${model.addHeaders}">
<sly data-sly-test="${headerList.count < model.headercolumn}">
<th>
<div class="cell-container">
<div class="cell-container--content">
<div class="preline">
                               ${header.headerTitle @ context='html'}
</div>
<div class="headline"></div>
                           ${header.headerContent @ context='html'}
</div>
</div>
</th>
</sly>
</sly>
<td class="table-spacer-column"></td>
</tr>
</thead>
<tbody>
<sly data-sly-repeat.table="${model.addRows}">
<tr class="roundedTop-sm">
<th class="cell-header">
<div class="cell-header--content">
                   ${table.title @ context='html'}
</div>
</th>
<td class="table-spacer-column"></td>
<sly data-sly-list.table="${model.addRows}">
<sly data-sly-test="${tableList.count < model.columns}">
<td>
<div class="cell-container">
<div class="cell-container--content">
                               ${table.content @ context='html'}
</div>
</div>
</td>
</sly>
</sly>
<td class="table-spacer-column"></td>
</tr>
</sly>
</tbody>

</table>

Avatar

Level 1
Level 1

<table>
<thead>
<tr class="header-content-row">
<td class="blank-cell"></td>
<td class="table-spacer-column"></td>
<sly data-sly-list.header="${model.addHeaders}">
<sly data-sly-test="${headerList.count < model.headercolumn}">
<th>
<div class="cell-container">
<div class="cell-container--content">
<div class="preline">
                               ${header.headerTitle @ context='html'}
</div>
<div class="headline"></div>
                           ${header.headerContent @ context='html'}
</div>
</div>
</th>
</sly>
</sly>
<td class="table-spacer-column"></td>
</tr>
</thead>
<tbody>
<sly data-sly-repeat.row="${model.addRows}">
<tr class="roundedTop-sm">
<th class="cell-header">
<div class="cell-header--content">
                   ${row.title @ context='html'}
</div>
</th>
<td class="table-spacer-column"></td>
<sly data-sly-list.cell="${row.cells}">
<sly data-sly-test="${cellList.count < model.columns}">
<td>
<div class="cell-container">
<div class="cell-container--content">
                               ${cell.content @ context='html'}
</div>
</div>
</td>
</sly>
</sly>
<td class="table-spacer-column"></td>
</tr>
</sly>
</tbody>

</table>

<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:Dialog"
cq:dialogMode="floating">

<content jcr:primaryType="nt:unstructured"
sling:resourceType="cq/gui/components/authoring/dialog">
<items jcr:primaryType="nt:unstructured">
<tabs jcr:primaryType="nt:unstructured"
sling:resourceType="cq/gui/components/authoring/dialog/tabs">
<items jcr:primaryType="nt:unstructured">
<properties jcr:primaryType="nt:unstructured"
jcr:title="Properties"
sling:resourceType="cq/gui/components/authoring/dialog/tab">
<items jcr:primaryType="nt:unstructured">

<!-- Header Configuration -->
<headercolumn jcr:primaryType="nt:unstructured"
fieldLabel="Number of Header Columns"
name="./headercolumn"
sling:resourceType="cq/gui/components/authoring/dialog/numberfield"
allowBlank="{Boolean}false"
minValue="1"/>

<addHeaders jcr:primaryType="nt:unstructured"
fieldLabel="Table Headers"
name="./addHeaders"
sling:resourceType="cq/gui/components/authoring/dialog/multifield">
<field jcr:primaryType="nt:unstructured"
sling:resourceType="cq/gui/components/authoring/dialog/compositefield">
<items jcr:primaryType="nt:unstructured">
<headerTitle jcr:primaryType="nt:unstructured"
fieldLabel="Header Title"
name="./headerTitle"
sling:resourceType="cq/gui/components/authoring/dialog/textfield"
allowBlank="{Boolean}false"/>
<headerContent jcr:primaryType="nt:unstructured"
fieldLabel="Header Content"
name="./headerContent"
sling:resourceType="cq/gui/components/authoring/dialog/textfield"
allowBlank="{Boolean}true"/>
</items>
</field>
</addHeaders>

<!-- Row Configuration -->
<columns jcr:primaryType="nt:unstructured"
fieldLabel="Number of Columns"
name="./columns"
sling:resourceType="cq/gui/components/authoring/dialog/numberfield"
allowBlank="{Boolean}false"
minValue="1"/>

<addRows jcr:primaryType="nt:unstructured"
fieldLabel="Table Rows"
name="./addRows"
sling:resourceType="cq/gui/components/authoring/dialog/multifield">
<field jcr:primaryType="nt:unstructured"
sling:resourceType="cq/gui/components/authoring/dialog/compositefield">
<items jcr:primaryType="nt:unstructured">
<title jcr:primaryType="nt:unstructured"
fieldLabel="Row Title"
name="./title"
sling:resourceType="cq/gui/components/authoring/dialog/textfield"
allowBlank="{Boolean}false"/>
<cells jcr:primaryType="nt:unstructured"
fieldLabel="Cells"
name="./cells"
sling:resourceType="cq/gui/components/authoring/dialog/multifield">
<field jcr:primaryType="nt:unstructured"
sling:resourceType="cq/gui/components/authoring/dialog/textfield"
name="./content"
fieldLabel="Cell Content"
allowBlank="{Boolean}false"/>
</cells>
</items>
</field>
</addRows>
</items>
</properties>
</items>
</tabs>
</items>
</content>
</jcr:root>