Wednesday, July 30th, 2008

Light-weight JSON Binding Framework

Category: JavaScript

<p>In my other life as a desktop application developer (which due to a mix of Fluid, AIR, Prism, canvas, SVG, and Flash is threatening to converge on my Ajax life) I’ve long been a fan of data-binding frameworks that make it easy to have a form automatically synchronize with backing data structures, saving you from the tedium of a dozen little “widget.getValue() – dataModel.setValue()” calls (or in the case of grids, etc. much more verbose and tedious plumbing).

Dojo and others frameworks have some interesting binding features, but if your favorite JavaScript framework lacks form data binding, check out Steven Bazyl’s small stand-alone JSON binding project: js-binding.

The project is just getting started, but it already has a few basic features that make it useful. For example, to convert this form:

  1. <form>
  2.   <input type="text" name="username"/>
  3.   <input type="text" name="email"/>
  4.   <input type="text" name="address.street"/>
  5.   <input type="text" name="address.city"/>
  6.   <input type="text" name="address.state"/>
  7.   ...
  8. </form>

into this object:

javascript
< view plain text >
  1. {
  2.   username: "...",
  3.   email: "...",
  4.   address: {
  5.     street: "...",
  6.     city: "...",
  7.     state: "..."
  8.   }
  9. }

You just need to write this code:

javascript
< view plain text >
  1. var myObject = ...;
  2. var myForm = ...;
  3. var binder = Binder.FormBinder.bind( myForm );
  4. binder.deserialize( myObject );

js-binder also has a built-in type conversion mechanism that, for example, allows you to easily integrate with a JavaScript date parsing library:

javascript
< view plain text >
  1. var binder = Binder.FormBinder.bind( myForm, {
  2.   date: {
  3.     // Date handler using datejs much improved parsing...
  4.     parse: function( value ) { return Date.parse( value ); },
  5.     format: function( value ) { return Date.toString( 'M/d/yyyy' ); }
  6.   }
  7. } );
  8. binder.deserialize( myObject );

The docs are concise but useful.

Related Content:

Posted by Ben Galbraith at 9:59 am
13 Comments

+++--
3.9 rating from 17 votes

13 Comments »

Comments feed TrackBack URI

I guess I’m so used to doing this the hard way that I don’t quite yet “get” what’s going on here. This goes on my learning list.
.
There’s no end to what you have to learn when you’re an Ajax guy.

Comment by Nosredna — July 30, 2008

data-binding totally rocks. I wrote a framework with bindings at the core of a client-side templating language and it is super productive. The templating language gets compiled into js on the server, but it allows for really nice stuff like:
<input type=”text” value=”#{path.to.value}”/>
or even directly in the html like
<h1>#{title}</h1>

So that the binding is specified in the html, similar to how Flex does it with MXML. I wish I had time to open source the code, but its all internal use right now. Great to see it becoming a prevalent concept in other js frameworks.

Comment by genericallyloud — July 30, 2008

we’re gonna see more of these. the question really has been why has it taken so long to get to this point? data binding is a fact of life on the server side.

Comment by ilazarte — July 30, 2008

The concept is absolutely sound. I also have done something similar, but using CSS rules for binding.

Comment by Ali Sullivan — July 30, 2008

@Nosredna This is not something worth studying.

http://js-binding.googlecode.com/svn/trunk/src/js/binder.js


var _isBuiltinType = function( obj ) {
var t = typeof( target );
return t == "string" || t == "number" || t == "date" || t == "boolean"
};

The serialize() method is also broken.

Garrett

Comment by dhtmlkitchen — July 30, 2008

dhtmlkitchen — There is a reason why the first bug I filed against myself is to clean up the code — it’s just about 200 lines of javascript written over the course of an hour or two :) First pass was just to get it working, next step is to make it pretty :)

If you have suggestions for how to do things better by all means share them.

Comment by sqrrrl — July 30, 2008

Spry framework from Adobe has some cool data binding techniques, which includes form handling, binding an XML/JSON data source to an HTML table and so on. Pretty interesting, but I am surprised why people aren’t raving about it.

Comment by ragjunk — July 31, 2008

I think I would probably rather do this data binding on the server using Spring or Apache Commons BeanUtils. BeanUtils for example would take something like address[0].city and automatically traverse the object graph using reflection and set the property. I guess it’s a matter of personal taste as to whether you want to do this on the client or server. I tend to prefer the server because I don’t have to worry about nasty browser issues.

Comment by mchammer — July 31, 2008

sqrrrl,

It’s not a matter of the code being ‘pretty’.
-
Placing target in makes typeof appear to be a function call. That is not the bug. That would be a ‘pretty’ issue.
-
The bug is in the second line of code:


return t == "string" || t == "number" || t == "date" || t == "boolean"

-
The typeof operator won’t return “date” for a built-in, in any browser. If a browser were to return “date” for typeof on a built-in, that would be a bug. It would, however, be possible for a browser to return “date” for a Host object. If this were to happen — and I have never observed this behavior — then _isBuiltinType would return true.
-
The typeof operator gets used further down. Using typeof property != "function" will determine that property is not (a built-in object that implements [[Call]]), though it may or may not be a Host object.
-
I would suggest removing the method _isBuiltinType and changing your approach entirely.

Comment by dhtmlkitchen — July 31, 2008

By pretty I meant removing dead/unused code and making sure what remains is necessary and well tested. That particular block was for an experimental feature (enumerating all the paths on an object graph) I hadn’t yet finished or tested and wasn’t even documented on the wiki, so I had no expectation that it was working nor would work, and the 0.x versioning should be a clue to anyone looking at it that there is no guarantee *every* line of code is going to be correct ;)

Anyway, I read through some of your writings on type checking and if I end up needing that code I’ll likely adopt much of what you’ve talked about.

Comment by sqrrrl — July 31, 2008

Nice elegant client-side binding for JSON. Love it!

Appcelerator uses this same concept, but in a declarative format. Note the JSON message (l:load) could be generated from either the client (as shown for illustration) or the server (more likely). The fieldset allows me to selectively bind only some form elements if I prefer.

Comment by MattQuinlan — August 6, 2008

looks like I forgot the “code” tag… sorry, reposting comment.

Nice elegant client-side binding for JSON. Love it!

Appcelerator uses this same concept, but in a declarative format.

Note the JSON message (l:load) could be generated from either the client (as shown for illustration) or the server (more likely). The fieldset allows me to selectively bind only some form elements if I prefer.

Comment by MattQuinlan — August 6, 2008

final attempt:


<app:message
name="l:load"
args="{person: {first_name: 'Joe', last_name: 'Smith'}}">
</app:message>

<div fieldset="user_info" on="l:load then bind[person]">
<input fieldset="user_info" name="first_name" />
<input fieldset="user_info" name="last_name" />
</div>

Comment by MattQuinlan — August 6, 2008

Leave a comment

You must be logged in to post a comment.