Data Driven UI

Tags

The following is a summary of research I’ve made while attempting to build a web application where each views would be generated based on how to organize data and how to organize its visualization.

The idea of separating data from HTML markup isn’t new, there has been many attempts

It is a follow up about one of the many tweets where I’ve made allusion about the same idea.

The article from @dan_abramov, titled "React as a UI Runtime" and Generate Vue.js components from JSON DOM Structure.

At first, I experimented with this JSFiddle, then, I implemented a more complete solution allowing me to keep memory a dataset (i.e. fetch once) in a given shape, and plug in how to assemble (i.e. change shape on screen, without re-fetching). Leveraging Vue.js’ design.

Description

Most FrontEnd tutorials and literature explains how to manually stitch HTML or JSX (now with React) together to make a view.

In most examples they show how to display values from numbers or strings. As strings. But rarely ways of "dressing up" more than one properties together dynamically.

That is also true for more advanced "component library" where we might want to re-use the same application layout for completely separate products. Not all projects uses exactly the same stack.

1. Value components

Components used to dress up complex values such as a circle with color. A date, where we plug in the user's locale and time zone, etc.

Here, shown inside an "UI-Value" project where we're publishing how to display a value.

We can use Storybook to work and visualize those components.

Notice the documentation for other developers to consume.

We can leverage Storybook’s "knobs" to visualize possible configuration options.

2. DisplayUnit and DataViewParent pattern

Which allows us to keep memory a dataset in a given shape, and plug in how to assemble.

Making views change completely by telling use this dataset (e.g. Vuex Store module in foo/bar/baz in rows), and just flip which DisplayUnitCollection to use and/or which top level DataView* component.

For example,

I want to put the contents of each rows’s content property inside a something value component.

And we can use that idea to describe a view. Such as a table with data.

A DisplayUnit can be seen as a descriptor to tell properties we want and how to organize the data, and with which we can pass into a "DataViewParent".

- The first column to use the each rows’s "`task_description`" property as
  value, and use "Task" as a label on top of the column
- The 2nd column to be labelled "Status", that is sortable, sorted by the value
  of "`completionProgress`" property, for each row cell, I want a
  "progress-trinary" component.
- The last column would be the date and time of the event in the current user's
  locale and time zone
headings:
  - label: 'task.label'
    prop: task_description
    component:
      type: router-link
      params:
        route: task-id-detail
      props:
        id: id
  - label: 'task.status'
    sortable: true
    sortBy: completionProgress
    component:
      type: progress-trinary
      props:
        value: completionProgress
  - label: 'task.completionState'
    component:
      type: progress-bar
      props:
        value: completionProgress
  - label: 'date.createdAt'
    component:
      type: date
      props:
        value: CreatedAt

With the description of the view, we can then pass some context and data and get a listing view.

rows:
  - completionProgress: 78
    task_description: Sending notification
    CreatedAt: 1580798072
    id: abc-123
    targetMachine: aaa-bbb-ccc
  - completionProgress: 100
    task_description: Updating dependencies
    CreatedAt: 1580794472
    id: abc-456
    targetMachine: ddd-eee-fff
    status: 1
session:
  locale: en-CA
  timeZone: America/Montreal
i18n:
  messages:
    en:
      task:
        label: Task
        completionState: Progress
        status: Status
      date:
        createdAt: Creation Date

DataViewParent

The "DataViewParent" are basically different ways of "dressing up" views.

One "DataViewParent" could be for listing a collection of objects, and another would be to display detail of only one entry.

List of all entries

In the example above, we could tell to list all entries as a table where we know the name and label for each columns, and how to format each rows.

And using the same pattern, we could describe a more detailed view for one of the currently selected item.

TaskStatusProgressCreation Date
Sending notification 78% Tue Feb 04 2020 at 01:34
Updating dependencies 100% Tue Feb 04 2020 at 00:34

Detail of one entry

Imagine the rows are the same as the example above, but where we want to display each properties on a table where the label is on the left, and the value on the right.

LabelProperty value
TaskSending notification
Status
Progress 78%
Creation Date2020-02-04

So, we can use the same data, and change how to display that data independently.

With this system in place, we could setup a completely different way of visualizing with the same data.

List of all entries

Using a top level DataView component from which we can iterate and list all entries, and optionally make them clickable to get to the "detail" view.

Detail of one Entry

Using a top level DataView component where the label is on the left, and the property is formatted on the right. "DataViewLabelProp"

3. Re-Usble common Web Application Layout ("AppLayout")

From one repository, sandbox to work on all Application Layout (or "Chrome") common in a web app; user icon, user options, sidebar, etc.

Output is a package we can publish and import from a host project: e.g. a nuxt project, a small vue project with vuex

(note that the merge request is no longer up to the same stage as shown in the following screenshots for packaging)

experiment merge-request

In the following screenshot, we can see that AppLayout contains many slots that we can configure at import time.

In the screenshots above, you’re looking at the process of themeing PanJiaChen/vue-admin-template to look like the WebApp I’m contributing to at my current employer so we can transparently migrate views from legacy.

Example how to make make use

The following is a video where I show PanJiaChen/vue-admin-template in use, then run the finished "themed" version where I package it, and import it inside a fresh Nuxt.js pro

  • First minutes shows library I'm importing from
  • Middle shows "frontend-bindings/vue-app-layout" as themed version
  • 3:01 Notice in "devDependencies" importing @frontend-bindings/conventions-use-bili
  • 4:11 Shows build process of packaging
  • 5:39 How to import into a new Nuxt.js project a packaged version of the vue-app-layout
  • 11:28 How to make host Nuxt.js project listen to vue-app-layout "logout" event

Video Publishing and importing vue-app-layout into a Nuxt.js project