So not too long ago I had a requirement to create an Table component for a client.
Before you shoot me down, I know this is generally a bad idea as the RTE in Sitecore has in-built support for Tables and there are Rich Snippets too. However there were a number of reasons that wouldn’t work well in this scenario, read on to find out why.
But, but RTE!?
There were some specific requirements which couldn’t be met by the RTE or Rich Snippets fully, we needed to:
- Add some specific mark-up, classes and wrapping divs around the table (some of this was for responsive requirements).
- Enforce Table header, body and footer rows
- Reduce the options for cells and rows to control better what content editors can do (for consistency).
- Be able to update the table mark-up easily in the future (so Rich Snippets wouldn’t work well here either)
- Limit the RTE options within a cell also to control better what content editors do.
Ok so how does the Component work?
So I did a bit research and thinking about various options and I liked Ben Golden’s answer on SSE. This provided a simple solution using Sitecore’s standard item and child item architecture to structure the tables.
So this is what I went for, it looks like so in Sitecore:
As you can see the structure is Table > Row > Cell(s) and the Table has 3 fields. More could be added easily if required in future.
There are no specific fields on the Rows but the Table has two checkboxes:
The cell template looks like so:
You can see the rowspan and cellspan options use a list of items as their datasource. We also use a custom RTE profile for the cell text to only allow a very small amount of RTE options.
Show me the Code
The following elements were required to build the component.
Rendering
The view is pretty simple. It just loops over the rows and outputs the cells. It also works out if a header and/or footer is required and if so renders out the correct mark-up for the first/last row. We are using Glass here so this may differ a bit for some sites. Note I’ve removed the code for row and cell span to make it easier to read:
The rendering itself is just a simple Sitecore View Rendering:
Models
The following are the 3 models which are used by the component, again pretty simple. The models are mapped with standard Glass mapping for the fields so I’ve not included that here:
What does it look like?
All being well you should see something like this output in the page:
In experience editor you can edit the cells like so:
Adding Rows and Cells quickly
This all works quite nicely but it can be time consuming to add rows and columns, especially if creating large tables. So there was a requirement to automate this. So I created a custom action which works in both experience editor and content editor. It’s fairly intelligent as does things like checking to see how many cells exist for current rows when adding new ones, orders the cells and rows automatically and names them for the user too.
Here is the code, note you will need to update the template ids for the rows and cells if re-using this code:
This is patched in for Content Editor like so:
<sitecore>
<commands>
<command name=”webedit:ext:addtablerows” type=”MyWebsite.Commands.AddTableRows, MyWebsite”/>
</commands>
</sitecore>
It can be added to experience editor by creating an custom experience button to call the command and assigning it to the rendering.
Is this a good idea?
Inevitably there will be requests to add more and more functionality to the table component over time to support things like alignment of cell content and so forth which adds further development time and complexity to the component. However for simple tables this does work fairly well and is an option where there are complicated design requirements or content editor restrictions required for Tables.
Hopefully this is useful for those considering building a Table component and weighing up the pros and cons of doing so.
Hi, this is really helpful, are you able to add the glass mapping configuration? I’ve got to this point but struggling to put the final pieces together here!
Glad you found this useful. Something like this should work, it might be you don’t need all these properties though:
public class TableCellMap : GlassMap
{
public override void Configure()
{
Map(x => ImportType
x => x.Field(y => y.Text).FieldName("Cell Text"),
x => x.Field(y => y.RowSpan).FieldName("Rowspan"),
x => x.Field(y => y.Colspan).FieldName("Colspan"));
}
}
public class TableMap : GlassMap(),
{
public override void Configure()
{
Map(x => ImportType
x => x.Field(y => y.HasHeaderRow).FieldName("Has Header Row"),
x => x.Field(y => y.HasFooterRow).FieldName("Has Footer Row"),
x => x.Children(y => y.TableRows));
}
}
public class TableRowMap : GlassMap(),
{
public override void Configure()
{
Map(x => ImportType
x => x.Children(y => y.TableCells));
}
}
Thanks for getting back to me so quickly, much appreciated!
The type or namespace name ‘GlassMap’ could not be found (are you missing a using directive or an assembly reference?
Apologies for the potentially stupid question, but is this code reliant on a separate namespace that I should be calling on?
I think we had an class that wraps SitecoreGlassMap<> and uses the fluent mapping. It depends what version of Glass Mapper you are using but here is an example of using it: https://blogs.perficient.com/2018/10/29/glass-mapper-part-1-of-2-what-it-is-and-how-to-use-it/