Web user interfaces have become much more complex than they were a couple of years ago. Complex SPAs using multiple vendor widgets needing to work with open source widgets etc., are taxing developers and taking a toll on their productivity. There is a need for a development paradigm that frees developers from this grinding exercise and makes developing web applications a fun experience. Enter Web Components. Web Components is a w3c specification. It helps developing web UI applications in a modular way.
The approach proposed here suggests we first write a set of state transitions for our UI application. So for the To-Do application which has a screen mock-up like:
I assume that the following are the required state transitions.
|Initials State||Pre-Event||Processor||Post-Event||Final State|
Note that I have identified four application states:
readyForAddSelectUnselectDelete. The state
readyForAdd, for instance, implies only add events can be emitted from this state, while the
readyForAddSelect state can only emit add and select events, etc.
The steps for the UI development include:
- Set up an HTML layout file for the UI application identifying the locations for the custom elements to be backed by the web components.
- Add script tags to the HTML file to reference the web component files.
- Write code in the
processor()functions to communicate with the web components via the corresponding custom elements.
- Add the state machine controller code.
1. To-Do application Web UI Layout Template
The web UI template corresponding to the above mock-up that will be using for our To-Do app is:
This template is not to be confused with the HTML Template feature of the Web Component specification. The above is just a UI layout for our application. Note that I have identified three custom element tags usage — input-comp, checkbox-group-comp and button-comp. The attributes used in these tags follow the APIs published by the corresponding web components.
2. Web Components
The source for the three web components are:
Note that for brevity of discussion, I am not using the Shadow DOM feature of web components.
CheckboxGroupComp class handles three actions — create, delete, and update. After the action is performed, it writes back the items count and selected items of the checkbox group to the data-response attribute.
3. Events and States Configuration
The states are configured in
appStates object sets the visibility status of the various components. So, it acts as a “View” in the MVC pattern.
The events are configured in todoApp.js like:
Note that I have used the
nextState() function in the
appEvents object instead of in the
appStates object since we see that only an event knows what the next state should be. Also, note that the
process() functions are used for the pre-events, and the
nextState() functions are used for the post-events. This, again, follows directly from the state transitions table.
4. Processor Functions
It is interesting to note that the
process() functions communicate with the custom element tags by posting their JSON data to the data-request attribute and collect a JSON response at the data-response attribute. The processor functions read the JSON data stored in the data-response attributes using a utility object, called
The source for
appData (defined as a const in todoApp.js):
appData object acts as a “Model” for the MVC pattern.
The engine of our state machine consists of these simple controller functions (in todoApp.js):
handleAppEvent() function listens and receives all the HTML DOM events (pre-events), including those raised by the web component. Note that even if Shadow DOM is used, we can still receive the events at the custom element (see Eric Bidelman). The callback function,
handlePostEvent(), handles all post-events.
Note that for brevity of discussion the
CustomEvent that is created above is used merely as a data transfer object and routed to the appropriate process function via the
stateTransitionsManager() function. If these custom events are dispatched then all the process() functions should be updated to listen to these events.
How One Transition Works
When the user performs an action on the screen the following steps are triggered:
- HTML DOM event (pre-event) is captured in the
- This event is wrapped in a custom event and sent to the
appEventsconfiguration and calls the required processor function passing it a callback function.
- The processor function communicates with the required web components and determines and creates a custom event (post-event) and passes it to the callback function,
handlePostEvent()function uses the
appEventsconfiguration and calls the
nextState()function uses the
appStatesconfiguration to set the visibility status of a web component.
- The screen is now ready to receive the next user action.
A demo of the application is available at TodoApp. As the user walks through each transition listed in the table above, they can also view the result of each step on the same page as a log message.
All the source for this article is available for download in GitHub.
A new approach to developing web UI applications using the state machine and MVC patterns is proposed. The approach is demonstrated for developing the TodoMVC application. Use of the Web Components is shown to further enhance the modular nature of the resulting application.
A uniform mechanism to communicate with the web components via data-request and data-response custom element attributes is found to enable state transitions as per the design. The state transitions table is shown to serve as a requirements aid, a development aid, and as a test case aid.
Readers interested in exploring the use of web components for the To-Do app can checkout Polymer TodoMVC. Readers interested in using the Shadow DOM feature of the web components specification can checkout this video — Web Components: It’s about Time.