Creating a custom item with various subtypes

I am currently implementing a data table element using custom elements (web components). The table may have different types of cells (text, number, date, etc.), which are used to render each row.

eg

<my-table>
    <my-table-cell-text column="name"></my-table-cell-text>
    <my-table-cell-date column="dob" format="YYYY-MM-DD"></my-table-cell-date>
    <my-table-cell-number column="salary" decimals="2"></my-table-cell-number >
</my-table>

I also have a class MyTableCellthat all elements of the cell expand. This is great for sharing common functions, however styling can be a pain, because each cell type is its own html tag. I am currently adding the css class when expanding MyTableCell, but for the argument, let's say I don't want to do this.

An ideal solution would be to be able to extend the user element using a keyword is, for example <my-table-cell is="my-table-cell-text">, but this is only allowed for inline html elements .


I can think of 3 approaches to solving this problem:

  • It has a syntax similar to <input type="">, but it works a lot more, because you no longer extend the base class, but rather create variations of the same element, and this means that you need a special way to register different options, something like staticMyTableCell.registerType

  • , <my-table-renderer-text> <my-table-cell>. , , , , .

  • , <my-table-cell type="text">, - document.createElement('my-table-rendener-'+ type). 1, , 2.


? - ?

+2
2

, <td> Customized :

<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>

-. :

//common cell
class DataCell extends HTMLTableCellElement {...}

//typed cell
class StringCell extends DataCell {
    renderContent() { ... }
} 
customElements.define( 'data-string', StringCell, { extends: 'td' } )

, <td>, , .

, -.

:

//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
Hide result

. , . , , ( ).

+4

NB: , .

(.. ) (optionnal) type:

<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>

... MVC:

  • (/ )
  • (, , )

:

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 + '"'
    }
}

( ):

  • , ( ).
  • ( ), ( Model).).).

v1:

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()
    }
} 

:

//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>
Hide result
+1

Source: https://habr.com/ru/post/1673469/


All Articles