Concept

Generated by: Projection Consumed by: Renderer

The model describing the rendering content.

Design impact

The design of Render Model impacts

  • Projection
    • Implementation of all projections, as projection may decorate the compose callbacks
  • Renderer
    • API of Renderer, as its the input of Renderer
    • Implementation of all Renderer

Diagram

Render model sample

{
  table: {
    attributes: { /* <table/> attributes */ },
    caption: {
      attributes: { /* <caption/> attributes */ },
      content: {
        Component, /* Black box component for the content type */
        props: { /* Properties for the content */ },
        events: { /* event handlers on the content */ },
      },
    },
    colgroups: [{
      key: 'default', /* <colgroup/> key */
      attributes: { /* <colgroup/> attributes */ },
      cols: [{
        key: 'col-Foo', /* <col/> key */
        attributes: { /* <col/> attributes */ },
      }],
    }],
    thead: {
      attributes: { /* <thead/> attributes */ },
      trs: [{
        key: 'tr-0', /* <tr/> key */
        attributes: { /* <tr/> attributes */ },
        ths: [{
          key: 'th-Foo', /* <th/> key */
          attributes: { /* <th/> attributes */ },
          content: { /* <th/> content */ },
        }],
      }],
    },
    tbodies: [{
      key: 'default', /* <tbody/> key */
      attributes: { /* <tbody/> attributes */ },
      trs: [{
        key: 'tr-0', /* <tr/> key */
        attributes: { /* <tr/> attributes */ },
        tds: [{
          key: 'td-Foo', /* <td/> key */
          attributes: { /* <td/> attributes */ },
          content: { /* <td/> content */ },
        }],
      }],
    }],
    tfoot: {
      attributes: { /* <tfoot/> attributes */ },
      trs: [{
        key: 'tr-0', /* <tr/> key */
        attributes: { /* <tr/> attributes */ },
        tds: [{
          td: 'td-Foo', /* <td/> key */
          attributes: { /* <td/> attributes */ },
          content: { /* <td/> content */ },
        }],
      }],
    },
  },
}

Why another "Virtual DOM Layer"?

The concept of render model is similar to a virtual DOM of table. The reasons we want to have this layer are

  1. Projection grid is targeting for framework neutral, we shouldn't make assumption on which virtual DOM implementation is used by the renderer.
  2. Projection grid is focus on an HTML table. Bringing in unrelated DOM concepts may add unnecessary complexity to projection/renderer developers.

Table specific model v.s. Generic model?

Two design choices for render model.

Table specific model

Define the model with HTML table terms, e.g. TABLE, CAPTION, COLGROUP, THEAD, TBODY, TFOOT, COL, TR, TH, TD. (Refer to Render model sample)

Benefit

The concept defined in the model can map directly to the HTML tags. People knows exactly what attributes they can set to each object.

Limitation

Less flexibility for renderers to render the grid with non-table elements.

Generic model

Define the model with generic table terms, e.g. "table", "title", "columnGroup", "header", "body", "footer", "column", "row", "cell".

Benefit

The model is defined with abstract concepts, so that renderers may render the grid with any HTML elements.

Limitation

There's no well-known protocol for the attributes. We need to define a set of new concepts for projection developers to follow.

Sample

{
  attributes: { /* table attributes */ },
  title: {
     attributes: { /* title attributes */ },
     content: { /* title content */ },
  },
  columnGroups: [{
    attributes: { /* column group attributes */ },
    columns: [{
      attributes: { /* column attributes */ },
    }],
  }],
  header: {
    attributes: { /* header attributes */ },
    rows: [{
      attributes: { /* header row attributes */ },
      cells: [{
        attributes: { /* header cell attributes */ },
        content: { /* header cell content */ },
      }],
    }],
  },
  bodies: [{
    attributes: { /* body attributes */ },
    rows: [{
      attributes: { /* body row attributes */ },
      cells: [{
        attributes: { /* body cell attributes */ },
        content: { /* body cell content */,
      }],
    }],
  }],
  footer: {
    attributes: { /* footer attributes */ },
    rows: [{
      attributes: { /* footer row attributes */ },
      cells: [{
        attributes: { /* footer cell attributes */ },
        content: { /* footer cell content */ },
      }],
    }],
  },
}

Our choice

Our choice is to use the table specific model because

  1. Extensibility is one of the most important design goal. We don't want add additional burden for projection developers to learn the new concepts.
  2. Rendering the grid with non-table elements isn't a major scenario for grid. Most of the use cases turned out to be false requirement. E.g. sometimes people want to render the grid as a list of cards. The right way is to use a list view instead of grid view. List view and grid may have similar data model, but people should design the model and view separately. We shouldn't adapt a view to something looks different just to reuse the data model.
  3. Even if in some special case people want to have a custom renderer to draw the grid with non-table elements, they should also follow the semantic of the HTML table elements. Otherwise, they cannot be called a "Grid Renderer".

Multiple <TBODY/>, multiple <COLGROUP/> and <CAPTION/>

According to the HTML standard, a table may have multiple <TBODY/>, <COLGROUP/> and one optional <CAPTION/> elements. This is not very useful for common grid scenarios. However, our render model should support that. Some projection developers may use them in their extensions.

results matching ""

    No results matching ""