From version 4.0 Internet Explorer has had the ability to bind certain HTML elements to a client-side data source. Pretty much any data you can access with ADO you can use as a data source but the one we've used most commonly at work is XML. By adding some attributes to your HTML elements e.g.
<input type="text" datasrc="#dsoComposers" datafld="compsr_last"/>
you can get them to render out the data from the data source and, in the case of inputs, persist any changes back to the source. Additionally, if you have a multi-row data source and you bind it to a table the contents of the tbody tag are duplicated for each row.
This is very useful for making web applications because:
- you only send the raw data along with a small amount of rendering HTML to the client
- the client edits the data, adding/deleting rows without postbacks
- the client posts back structured data rather than a ton of awkwardly named querystring variables
- you need no presentation code for translating your data to or from HTML
All this considered I thought I'd have a go at creating a simple cross-browser version of this databinding functionality in jQuery with a limited feature set.
Features to implement
For this proof of concept I decided the features I would try and implement were:
- Support for JSON as a data source
- Repeat rendering of a table's tbody section for each item in an array of objects
- CSS class name based way of tying properties of the objects to HTML elements
- Rendering of property values within HTML elements innerHTML or value
- Attaching of event handlers to persist data changes on inputs back to the array data source
- Some ability to reflect programmatic changes to the underlying data source in the bound HTML elements
- Doing the above without needing to fully refresh the HTML every time
Use
Some "template" HTML...
<table id="info">
<thead>
<tr>
<th>Common name</th>
<th>Origin</th>
<th>First developed</th>
<th>Use</th>
</tr>
</thead>
<tbody>
<tr>
<td class="field[name]"></td>
<td><input type="text" class="field[origin]"/></td>
<td class="field[developed]"></td>
<td class="field[use]"></td>
<td><button class="field[delete]">Delete Row</button></td>
</tr>
<tr>
<td colspan="4" style="border-bottom: 2px solid #888;"><textarea class="field[comments]" style="width: 100%;"></textarea></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="4"><button id="add">Add Item</button></td>
</tr>
</tfoot>
</table>
...some data...
var data = [
{ name: 'Braeburn', origin: 'New Zealand', developed: '1950s, United States', comments: '', use: 'Eating' },
{ name: 'Bramley', origin: 'Southwell, Nottinghamshire, England', developed: 'about 1809', comments: '', use: 'Cooking' },
{ name: 'Cox\'s Orange Pippin', origin: 'Great Britain, New Zealand', developed: 'c. 1829', comments: '', use: 'Eating' },
{ name: 'Empire', origin: 'New York', developed: '1966', comments: 'Lovely white subacid flesh. Tangy taste.', use: 'Eating' },
{ name: 'Granny Smith', origin: 'Australia', developed: '1868, Australia', comments: 'This is the apple once used to represent Apple Records. Also noted as common pie apple.', use: 'Eating or cooking' }
];
...and a small amount of JavaScript...
$(document).ready(function(){
$('#info').databind(data);
});
The add button handler looks like this...
data.push({ name: '', origin: '', developed: '', comments: '', use: '' });
$('#info').databind(data);
...any code making programmatic changes to the data must recall databind to refresh the bound HTML elements.
Demo
I've set up this quick proof of concept here. I haven't looked at how it performs with large arrays of data but I expect the answer would be badly.
Going forward there may be scope for turning this into a proper jQuery plugin with support for other types of data source and the ability to bind an arbitrary group of elements to some data rather than just a table.