The simplest web page today includes at least 3 different languages, each with its own syntax and design outcomes. HTTP for markup, CSS for styling and JavaScript for logic. This article introduces readers to a new way of thinking about how we can create web content in a way that only one of these technologies are used for markup, styling and logic.
Introduction
The Internet has a long and interesting, naturally evolving history. With this evolution came a legacy that we are living with today. Various challenges in the history of web development were solved in different ways by different technologies. It is not uncommon for a single web page today to include HTTP, CSS, JavaScript, SVG and maybe a few other types of technologies. This article introduces a unified way of looking at how we can develop web content so that we use one primary language, one syntax and no more context switching while we work.
Background
When doing web development, I find myself having to jump between CSS, JavaScript and HTML markup quite a lot. I also spend a lot of time wondering what the best way is to do certain things. For example, if I have to change the color of a label based on valid user input - does that belong purely in CSS, or do I change the attribute in JavaScript, or do I create a different style and change the style name from JavaScript. There are so many different ways of doing the same thing because the boundaries of these technologies are overlapped. So I thought that there has to be an easier way to do this.
Firstly, the realization that the same information that is typically contained in HTML markup, can also be represented in a JavaScript object quite easily. Both are hierarchical in nature, both HTML and JavaScript have sub elements, and attributes. Take this simple web form that allows a user to enter some basic information:
The web page includes a bit of styling, and also some arbitrary logic which is executed when the button is clicked. One could build this web form using HTML, a stylesheet, and a JavaScript file, but look at the following JavaScript objects to see how we can represent the same information using only JavaScript:
var dataObject = {
InvoiceDate: '2016-01-15',
Customer: 'Andy Jones',
DeliveryAddress: '273 Honeydew Boulevard, 22178'
}
var viewObj = {
head: {
title: 'union.js - view-model example'
},
body: {
header: { tag: 'h4', value: 'Order Details:' },
lblInvoiceDate: { tag: 'label', value: 'Invoice Date: ' },
editInvoiceDate: { tag: 'input', type: 'date',
mapObj: dataObject, mapAttr: 'InvoiceDate' },
br: {tag: 'p'},
lblCustomer: { tag: 'label', value: 'Customer: ' },
editCustomer: { tag: 'input', mapObj: dataObject, mapAttr: 'Customer'},
br2: {tag: 'p'},
lblAddress: { tag: 'label', value: 'Delivery Address: ' },
editDeliveryAddress: { tag: 'input', mapObj: dataObject,
mapAttr: 'DeliveryAddress'},
br3: {tag: 'p'},
buttonSave: {tag: 'button', value: 'Update', onclick: function(page) {
alert(JSON.stringify(dataObject));
page.style.body.color = 'green';
}}
},
style: {
body: {"font-family": "Verdana"},
label: {width: '170px', display: 'inline-block'},
input: { width: '200px', 'border-radius': '5px', 'border': '1px solid black'}
}
}
The first thing to notice on the viewObj
is that we have a head
, body
and style
attributes. These are defined as objects themselves, and contain a series of sub objects that represent all of the elements required on the web page.
Also, when the event fires, you will notice that the JavaScript only references what is defined in JavaScript. There is no DOM traversal required.
union.js is a small library that I contribute to, which allows you to create web content using JavaScript objects as the primary coding element. HTML and CSS are emitted from the structure of your JavaScript objects when a page is loaded, and everything is kept nicely in sync. Changes made by users are automatically reflected in your JavaScript objects, and changes you make to your objects are automatically reflected in HTML and CSS.
This eliminates the need for document traversal.
union.js is hooked up in an HTML stub as follows:
The buildPage
method accepts the JavaScript object that contains the information about the page itself. This can be seen as a view object in a MVC pattern. In this example, the object is the dataObject
, the view is the viewObj
and the controller function is performed by union.js.
Here is a working example:
Points of Interest
In developing union.js, it was interesting just how much of what was needed, was already defined in the web standards. It is because of this reason that the minified copy of union.js in only 2.3 KB in size.
union.js makes use of proxy classes to provide any events with access to values that were altered by users. If a user changes a value on the web page like the customer name for example - the changed value can be accessed with this.lblCustomer.value
. No need for weird HTML DOM traversal.
Similarly, of a separate data object is used, the data object is updated from the HTML representation before any of the code on the page fires. It is for this reason that the message box in the working example shows values that were changed on the HTML page.
History
- 23rd August, 2022: Initial version