Sam Elsamman

Nerdy Musings and Other Stuff

Bindster: A Data Binding Framework for JavaScript

When I started writing Bindster in 2009, JavaScript was still considered “glue” code that added some interactivity to web pages. Pages were mostly served up with data already embedded in them through server-based templates. Communication with the server mostly consisted of posting forms or AJAX calls that returned HTML to be injected. There were some client-side template solutions though they were unidirectional and you were still responsible for getting data from form elements on the web-page by handling the events that these elements generated.

Having written some pretty complex web applications, it was clear to me that this hodge-podge way of creating a richer user experience had to come to an end. It had to end because it really wasn’t that rich of an experience to start with. Pages would sometimes repaint when forms were used and sometimes they would update in place. Needless to say the code was overly complex with no generally accepted design patterns.

A much cleaner solution was to have all user interface logic in JavaScript, on the browser, making course-grain AJAX requests to the server passing in and returning just the data. The server would deal with the data and secure transactions and the browser would deal with the user interface. The missing ingredient was a better way to marshal data between the page and data structures so one would not be dependent on form submissions or messy interfaces with form elements. In a nutshell Bindster is a bidirectional client-side template system for HTML that transfers data back and forth between DOM elements and a JavaScript data structure. It handles iteration, conditional display, parsing, formatting validation and even lets you create custom HTML elements.

As I am far into my second significant application using Bindster I am absolutely convinced that data-binding frameworks are central to the evolution of web-based software development. My productivity, level of robustness and agility have all improved dramatically as a result of using Bindster. I am not going to cover Bindster in detail as that has been done on the Bindster web-site but rather talk a little bit about how to think about data binding frameworks and how Bindster differs from other frameworks released since I started writing Bindster.

Thinking the Data Binding Way

For years programming had consisted of input -> compute -> output. Dan Bricklin and Bob Frankston decided that this approach was not going to be very useful for end-user computing and so VisiCalc, the first spreadsheet was born. Anyone who uses a spreadsheet knows that you think differently about things with a spreadsheet. What you see on your screen is the result of a series of calculations on your data which represents the current “state” of the problem being solved. If you change that state, everything is recomputed.

This is exactly the way you think of things when you use a data-binding framework. You get your data setup based on the state of things as returned by the server and then you just map it to the display through data-binding. The magic of data-binding, however, is that unlike a spreadsheet this mapping is bidirectional. Anywhere you map to editable form elements the data will be updated as the user changes it. So the state of your application changes as a result of one three things:

  1. Data is retrieved from the server
  2. The user changes the data bound through form elements
  3. The user requests a specific action to take place via a button/link and your code kicks in

This is different than the approach taken by other modern client-side tools like Backbone or jQuery where the code drives everything. With data binding, you don’t need to render views or deal with events other than those related to explicit user actions like the press of a button or clicking on a link. This results in a more functional programming experience where everything is based on the state of the data model.

Binding Frameworks

At present there are two other significant binding frameworks – Knockout.js which was in part inspired by Silver Light and Angular which was developed by Google. Given that Angular has the support of Google it becomes the de-facto standard in JavaScript data binding to which all must be compared and I will focus my brief comparison on Angular.

These are some of the key differences between Angular and Bindster.

  • Semantics – Angular is focused on being an extension to the HTML language, “What HTML would have been, had it been designed for building web-apps”. Its features are largely embedded into the syntax of HTML and are declarative in nature. Bindster on the other hand is based on semantics that can be defined either in JavaScript code or in HTML. This allows the developer to determine the level of separation between markup and binding semantics and also allows some aspects of the binding to be rule-based through the use of selectors or be embedded in object class definitions.
  • How they bind – The magic that binding frameworks provide is to know when data has changed and to then update the screen so the change is visible. Angular does this by keeping a digest of the data and then looking to see if that has changed and then re-rendering elements connected to the modified data. The data is examined every time an event occurs. Bindster takes the opposite approach. It re-renders every time an event occurs. It only renders portions of the screen that are visible and it only updates the screen if the data value does not match a cached copy for that particular display element. Both approaches have their pluses and minuses. If you have very large amounts of HTML and very little data, the data-trigger approach of Angular can be faster. If you have very large amounts of data the display-trigger approach of Bindster can be faster. In practice both work well.
  • Scope – In Angular you define specific scopes for different parts of your application. The scope determines what you can bind to. Each section has its own controller and the scope is connected to that controller by virtue of being declared in HTML. If you have a model you just add the model as a property of the scope. With Bindster the connection between model, view and controller is made in JavaScript . Usually the same model and controller are used for the entire application. Both the model and the controller are in scope when referenced in binding or event handlers (e.g. onclick). This comes back to the difference in semantics vs. syntax orientation of the two frameworks. In practice this leads to lots of smaller components with Angular which can bring modularity to the application at the expense of maintaining more moving parts.
  • Directives vs. Mappers. In Angular only the core data binding is incorporated into Angular itself and other parts you might need to bind complex items (such as iteratively binding to arrays of values or custom elements are handled by directives. Directives are pieces of JavaScript that can receive data from parameters in the markup and interact with the Angular core to manipulate the DOM and inject HTML.
    Bindster uses three different techniques to cover the capabilities in directives:
    • Iteration and conditional inclusion of DOM elements is part of the core of BINDster.
    • Custom tags are created in mark-up rather than using JavaScript and are called Mappers. They are mini-HTML templates that “map” to a custom tag with custom attributes. The attributes you specify when using the custom tag are substituted into the template, creating a macro-like capability. They can also be used to wrap widgets like Google Maps or embedded video. Mappers are useful in their own right without using any data binding features.
    • DOM Controllers are used to create a custom interface between the binding mechanism and DOM elements to facilitate new controls such as sliders.
  • Validation/Formatting – In Bindster, parsing, validation and formatting are core parts of the binding mechanism. They are surfaced as script that executed when data is bound to or from the form element. The script can be defined inline (usually as calls to common code (e.g. b:parse=”formatCurency()”) or they can be attached from JavaScript using css selectors or they may be attached to class definitions so they are automatically incorporated where every they are bound. One of the subtle differences between Angular and Bindster is that in Angular when you get a validation error, the referenced property in the model is set to “undefined”. In Bindster, the model is simply not updated. What this means is that any calculations based on the model will continue to work even if there is a validation error rather than potentially throwing exceptions as undefined is thrown into an expression.

While these differences are significant both frameworks are capable of garnering huge productivity improvements. My preference for Bindster and the reason that I continue to use and support it are that I feel the ability to create custom tags through mappers and the ability embed more of the binding functionality into script and in particular the object model makes it useful enough to continue using Bindster. This latter function has become particularly important for object oriented development where I want more and more rules to be embedded in the object definition rather than the markup.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>