Observable Arrays and Observable Objects

Support for Observable Arrays and Observable Objects is provided by jquery.observable.js


It provides a way of mutating JavaScript arrays or objects in a way that raises corresponding change events, which other code may be listening for. This is key to providing reactive UI driven by data changes, and can be used in many other scenarios, such as creating changesets of data-changes to be round-tripped to the server via JSON services or similar.


Observable data is used by data linking and by JsViews in order to enable interactive data-driven views. JsViews integrates jQuery templates and data link, so that observable changes to data can automatically trigger updates in UI rendered by jQuery templates. Use of JsViews by the Grid can enable HTML rendered by the grid to update whenever the data is sorted, filtered, or mutated, without additional code. Where appropriate, the update can be incremental, without the performance hit of re-rendering the whole list of items.


Observable API


Usually you just want to make one or more observable changes to an object or an array:

$.observable( myObject ).setField( "someField", value );
$.observable( myArray ).pop();


$.observable( data ) gives you as set of mutation methods for your data - based on whether it is an array or an object.


If you want, can hold on to it, as in

var myObservableArray = $.observable( myArray );
myObservableArray.push( item ).shift();


If needed you can get your raw data item back:

myArray ===; // true


...But usually you won't bother. Just use $.observable( data ).foo() each time.


Supported mutation methods


pop, push, reverse, shift, unshift, sort, splice. (Signatures identical to standard array methods) 

move( fromIndex, numItems, toIndex)

replace( newItems )  



setField( path, value )

Note: path can be the field name, or can drill into child objects, as in setField( "", "Seattle" );


Associated change events



Note: associated eventArgs provides the method name and associated data or indexes, such as:

{ change: "add", newItems: [addedItem] } 



Note: associated eventArgs provides the path and the value

{ path: "", value: "Seattle" } 



You can add methods for arrays or objects by extending $.observable.array or $.observable.object...


Example (This is how the replace method was added in jquery.observable.js):

    replace: function( newItems ) {
        this.splice.apply( this, [].concat( 0,, newItems ));
        return this;


jQuery Templates Integration

The JsViews and JsRender implementation of jQuery templates allows the following:


// Get concatenated string obtained by applying the template to the data item (if object) or items (if array).
var htmlString = $( "#myTemplate" ).render( myData );

// Insert the html into the DOM
$( "#myContainer" ).html( htmlString ); 

// Activate the rendered HTML elements
$( "#myContainer" ).dataLink( myData );


The effect of data linking (activation) is to add bindings to both the data and the rendered HTML, so that: 

  1. If myData is and array, then observable changes to the array will cause the templates engine to render incrementally into to the DOM to remain in sync with the data array
  2. If myData is an object, then declarative data linking in the template allows fields in the HTML to update when observable changes are made to the field of the data
  3. Declarative data linking also allows two-way binding to apply so user value entered in inputs etc. can immediately propagate to the underlying data
  4. The above binding applies also to nested template, arrays of data, and hierarchical data, so that values of fields on data items in an array, or modifications to nested arrays will also propagate without additional code being required 


As a result, the following code will immediately trigger incremental insertion of a new rendered item under "#myContainer" above:


// Add item and trigger any rendered templates in the DOM to insert corresponding row
$.observable( myData ).push( item );


Grid and DataSource Integration


Key changes to DataSource:

 Listen to observable changes on input data (local data source):


$.dataLink( this.options.input, function() {


Make observable changes when changing 'output' data:


this.options.source( request, function( data, totalCount ) {
    $.observable( that ).setField( "totalCount", totalCount );
    $.observable( ).replace( data );


Key changes to Grid:

 Grid depends only on data array, not on DataSource, and responds to observable changes on that data:


refresh: function() {
    tbody.html( $.render( template, source ))
        .dataLink( source );




The grids reflect the changes to the data on paging etc., as a result of observable collection events integrated with templates (without additional code).


Demo: Grid and Observable Array


Key code:

$( "#developers-data" ).grid({
    selectMode: "single",
    columns: [ "firstName", "lastName", "country" ],
    source: developersInput

function deleteSelectedDeveloper() {
    $.observable( developersInput ).splice( index, 1 ); prevIndex );


The grid reflects the changes, as a result of observable collection events.


Demo: Grid and Editable Data


Key code:

$( "#developers-data" ).grid({
    selectMode: "single",
    columns: [ "firstName", "lastName", "country" ],
    source: developersInput,
    select: onSelectChange

function onSelectChange( event, args ) {
    $( "#developerDetail" )
            $( "#detailViewTemplate" ).render( )
        .dataLink( );
<script id="detailViewTemplate" type="text/x-jquery-tmpl">
    <input data-jq-linkfrom="firstName" data-jq-linkto="firstName" value="${firstName}"/>


Full editing through Master-Detail UI. The grid reflects the changes, as a result of observable events.


Demo: Multiple Views


Full set of demos:


Follow-on work


I've been collaborating with Boris to refine $.observable in ways that are important to Grid (and to jQuery generally).  We'll post this work (including demos) to the wiki soon.


The aspects we're covering are:


-- Brad Olenick (