I am currently implementing a data-table element using custom elements (web components). The table can have different types of cells (text, number, date, etc) that are used
What could be done is using <td>
Customized Built-in Element:
<table is="data-table>
<tr>
<td is="data-string">Bob</td>
<td is="data-date">11/1/2017</td>
<td is="data-number">44<td>
</tr>
</table>
All extensions share the same prototype ancestor. Example:
//common cell
class DataCell extends HTMLTableCellElement {...}
//typed cell
class StringCell extends DataCell {
renderContent() { ... }
}
customElements.define( 'data-string', StringCell, { extends: 'td' } )
This way all cells extend the same <td>
element, share a common prototype but have their own method implementations.
You can override shared method, and shared method can call specific method of the derived prototype object.
See a running example here:
//table
class DataTable extends HTMLTableElement {
constructor() {
super()
console.info( 'data-table created' )
}
}
customElements.define( 'data-table', DataTable, { extends: 'table' } );
//cell
class DataCell extends HTMLTableCellElement {
connectedCallback() {
console.info( 'cell connected' )
if ( typeof this.renderContent === 'function' )
this.renderContent()
}
}
//cell string
class StringCell extends DataCell {
renderContent()
{
console.info( 'data-string render' )
this.innerHTML = '"' + this.textContent.trim() + '"'
}
}
customElements.define( 'data-string', StringCell, { extends: 'td' } )
table {
border-collapse: collapse ;
}
td, th {
border: 1px solid gray ;
padding: 2px
}
<h4>Test Table Extension v1</h4>
<table is="data-table">
<tr>
<th>Id <th>Name <th>Age
<tr>
<td>1 <td is="data-string">An <td>20
<tr>
<td>2 <td is="data-string">Bob <td>31
Note: If you don't want type extension you can also do it with custom tags. The idea is to have a common prototype and different custom elements that share it (thanks to standard prototype inheritance).
NB: This answer is separeted from the other as it's quite extensive by itself and totally independant.
If you use Autonomous Custom Elements (i.e. custom tags) with a (optionnal) type
attribute:
<data-table>
<data-row>
<data-cell>1</data-cell>
<data-cell type="string">An</data-cell>
<data-cell type="number">20</data-cell>
</data-row>
</data-table>
...you could use the MVC pattern:
Example with generic and string view:
class CellView {
constructor ( view ) {
this.view = view
}
render () {
//default rendering
}
}
//String View
class CellStringView extends CellView {
render () {
console.info( 'special rendering', this.view )
this.view.innerHTML = '"' + this.view.textContent + '"'
}
}
In the custom element definition (which can be viewed as the Controller):
Example with a Custom Element v1 class:
class CellElement extends HTMLElement {
constructor () {
super()
//create cell
switch ( this.getAttribute( 'type' ) )
{
case 'string':
this.view = new CellStringView( this )
break
default:
this.view = new CellView( this )
}
}
connectedCallback () {
//render cell
this.view.render()
}
}
Below is a live snippet:
//View (MVC View)
class CellView {
constructor(view) {
this.view = view
}
render() {}
}
//String View
class CellStringView extends CellView {
render() {
console.info('special rendering', this.view)
this.view.innerHTML = '"' + this.view.textContent + '"'
}
}
//Element (MVC controller)
class CellElement extends HTMLElement {
constructor() {
super()
//create cell
switch (this.getAttribute('type')) {
case 'string':
this.view = new CellStringView(this)
break
default:
this.view = new CellView(this)
}
}
connectedCallback() {
//render cell
this.view.render()
}
}
customElements.define('data-cell', CellElement)
data-table {
display: table ;
border-collapse: collapse ;
border: 1px solid gray ;
}
data-row {
display: table-row ;
}
data-cell {
display: table-cell ;
border: 1px solid #ccc ;
padding: 2px ;
}
<h4>Custom Table v1</h4>
<data-table>
<data-row>
<data-cell>Id</data-cell>
<data-cell>Name</data-cell>
<data-cell>Age</data-cell>
</data-row>
<data-row>
<data-cell>1</data-cell>
<data-cell type="string">An</data-cell>
<data-cell>20</data-cell>
</data-row>
<data-row>
<data-cell>2</data-cell>
<data-cell type="string">Bob</data-cell>
<data-cell>31</data-cell>
</data-row>
</data-table>