• .NET Developer Tools DevTools

    UI controls for ASP.NET AJAX, MVC, WPF,
    Silverlight, Windows 8 and Windows Phone

  • Hybrid Mobile Development Icenium

    Cross-platform Mobile Development Tool
    with cloud-based architecture

  • HTML5 / JavaScript Development Kendo UI

    Everything you need to build sites and
    mobile apps with JavaScript and HTML5

  • Testing Tools TestStudio

    One easy tool for Functional, Performance,
    Load and Mobile software testing

  • Web Presence Platform Sitefinity CMS

    Everything for your online business - content
    management, ecommerce, emarketing

  • Agile Project Management TeamPulse

    Simple and intuitive project management
    and collaboration software

Contact us

We are here for you.
  • usa+1‒888‒365‒2779
  • uk+44‒20‒7291‒0580
  • bg+359‒2‒8099850
  • de+49‒89‒2441642‒70
  • au+61‒2‒8090‒1465
  • emailsales@telerik.com
Your account Access to your products, updates and support
Telerik Product Families
  • Your Account
    Your Account
    Log in
  • ABOUT US

    About Telerik

    • Company
    • Press Center
    • Customers
    • Community
    • Careers
    • Contacts
Kendo UI - The way of HTML5
Products ▼
Kendo UI Web Kendo UI Mobile Kendo UI DataViz Server Side Wrappers
Demos Purchase Download
Blogs Documentation
Support ▼
Premium Forums StackOverflow Forums
Resources ▼

Featured Resource

Kendo UI Dojo


Blogs Code Library Demos Documentation FAQ Testing
Premium Forums Roadmap User Voice Videos Webinars More Resources
Contact Us Search
 

Blogs

Wrapping A Backbone.Collection In A kendo.data.DataSource

Thursday, February 07, 2013 by Kendo UI Team Blog | Comments 3

In my first post about learning kendo.data.DataSource , a commenter asked me about the differences between this and a Backbone.Collection. He also wondered if there would be any value in creating an adapter that could turn a Backbone.Collection in to a Kendo UI DataSource.

The value that a DataSource wrapper provides, beyond integrating Backbone and Kendo UI from a visual perspective, is in the data-binding and other logic that Kendo UI provides in it's widgets and control suite. I've integrated them in previous projects for clients, but it has always required custom code for each situation that I was tying together. I don't like repeating code and I don't like having to manually wire things together. So it makes sense to build an adapter between a Backbone.Collection and Kendo UI DataSource.

Building A Custom Transport

The DataSource object has a lot of potential entry points for extension and customization. This can make it difficult to know exactly what to start with and what direction to head. But in looking through the documentation and demos , I noticed that there's a trend in changing how the DataSource works with different types of back-end data: a transport object.

According to the documentation, a transport

Specifies the settings for loading and saving data. This can be a remote or local/in-memory data.

This sounds like exactly what I want. Rather than having to deal with customizing the data-binding and other aspects of creating a full fledged DataSource, I can stick with the core CRUD operations of workign with my data's "back-end". In this, I'll just be pushing everything to and from a Backbone.Collection.

To get started, I dug through the documentation for transports and looked at a few examples that some co-workers sent to me. It turns out there is very little that I really need to do, though there is a lot that I could do.

To build a completely custom transport, I only need to provide an object literal to my DataSource instance, with basic CRUD operation methods:

  • Create
  • Read
  • Update
  • Destroy

A Custom Transport

var dataStore = new kendo.data.DataStore({

  transport: {
    create: function(options){
      // create a new entity with the `options.data` here
      // call `options.success(entity)` when I'm done
    },

    read: function(options){
      // send back all data as a simple JSON document or object literal
      // options.success(myData);
    },

    update: function(options){
      // update an existing entity with the `options.data` here
      // call `options.success(entity)` when I'm done
    },

    destroy: function(options){
      // destroy an entity identified with the `options.data` here
      // call `options.success(entity)` when I'm done
    }
  }

});

It can be as simple as this, but I need a little more than providing an object literal for a transport in my DataSource. I want to encapsulate all of the core options that I need for my Backbone DataSource while still allowing things to be customized. I also need to keep track of the actual Backbone.Collection being used as the backing store for the DataSource. To do all of this, then, I decided to create a custom class called kendo.Backbone.DataStore.

An Outline For kendo.Backbone.DataSource

At a high level, my custom DataSource type largely looks like the transport that I showed above. But instead of creating an object literal for it, I'm creating a new constructor function that can be used to create instances of the transport.

Outline Of BackboneTransport

var BackboneTransport = function(collection){
  this._collection = collection;
};

_.extend(BackboneTransport.prototype, {
  create: function(options){ /* ... */ },

  read: function(options){ /* ... */ },

  update: function(options){ /* ... */ },

  destroy: function(options){ /* ... */ },
});

I'm creating a new constructor function because I need the transport to hold on to the Backbone.Collection reference that I send to it, and I want every instance of my BackboneTransport to have it's own reference to the correct Backbone.Collection.

Note that I'm also taking advantage of JavaScript's prototypal inheritance in adding my CRUD methods to the prototype. To do this, I'm using the underscore.js extend method. This method allows me to easily add methods and data to an existing object using an object literal. In this case, I'm adding my CRUD methods to the BackboneTransport prototype, making these methods available to every instance of BackboneTransport.

As I said before, I want to provide a few default options for my DataSource and not just provide a transport implementation. To do this, I'm creating a kendo.Backbone.DataSource object that extends from kendo.data.DataSource.

A Custom DataSource

kendo.Backbone = kendo.Backbone || {};

kendo.Backbone.DataSource = kendo.data.DataSource.extend({
  init: function(options) {
    var bbtrans = new BackboneTransport(options.collection);
    _.defaults(options, {transport: bbtrans, autoSync: true});

    kendo.data.DataSource.fn.init.call(this, options);
  }
}); 

Here, I'm creatiing a namespace for kendo.Backbone so that I can attach my DataSource object.

I'm then extending from kendo.data.DataSource to create a custom DataSource that inherits directly from the original. This works very similarly to Backbone's extend method, but is provided by Kendo UI's DataSource in this case.

Within the init function (the Kendo UI equivalent of Backbone's initialize function), I'm creating a new instance of my BackboneTransport. I'm using this to set up a few default options and then forwarding the options to the super-type's init function in order to get the DataSource completely up and running.

The use of underscore's defaults method allows me to specify values for my options that will be used if those values have not already been provided in the options object. In other words, I can override these using the constructor for my DataSource:

Override Default Options

new kendo.Backbone.DataSource({
  autoSync: false // override the default that I set
});

Normally, I won't need to override this option, though. In fact, I usually want the autoSync option set to true so that any change made to the DataSource will be pushed to my BackboneTransport instance immediately.

Now that we have the outline for the custom Transport and DataSource covered, let's look at what it takes to fill in the CRUD operations for the transport.

Create

Creating a new model is fairly easy. Backbone.Collection has an add method that we can use for now. There is a create method as well, but this method will push data back to the server. Right now, I want to ignore the server communication that Backbone.Collection provides, and stick with an in-memory collection.

One thing we do need, though, is a "id" field and incrementing value. To keep this simple, we'll use a simple integer value and increment it every time we create a new model.

Create

  create: function(options){
    // increment the id
    if (!this._currentId) { this._currentId = this._collection.length; }
    this._currentId += 1;

    // set the id on the data provided
    var data = options.data;
    data.id = this._currentId;

    // create the model in the collection
    this._collection.add(data);

    // tell the DataSource we're done
    options.success(data);
  }

Read

Reading data is the easiest of all the code we have to add to the custom transport. Backbone.Collection provides a toJSON method that returns the models as an array object object literals, which is what the DataSource wants.

Read

  read: function(options){
    options.success(this._collection.toJSON());
  }

Update

Updating a model is fairly simple as well, but it does need a few steps to get it done. First, we have to find the model that we're trying to update. Since we are handed an object literal as options.data, we need to use the id that we added to the data to find the model. Once we have that, we can update the model as we normally would with Backbone.

Update

  update: function(options){
    // find the model
    var model = this._collection.get(options.data.id);

    // update the model
    model.set(options.data);

    // tell the DataSource we're done
    options.success(options.data);
  }

Destroy

Destroying a model is also fairly simple. As I noted in the "create" function's description, I'm only concerned with an in memory representation of the Backbone.Collection right now. Considering this, I'll avoid using the methods that actually destroy through the Backbone.Collection server communications. Instead, I'll just use the remove method to remove the model from the Collection.

Once again, we have to find the model by id since we are handed an object literal representation of the model.

Destroy

  destroy: function(options){
    // find the model
    var model = this._collection.get(options.data.id);

    // remove the model
    this._collection.remove(model);

    // tell the DataSource we're done
    options.success(options.data);
  }

Putting It All Together: A Demo App

Now that we have our custom transport and DataSource built, it's time to put together a simple demo application. As with my first two blog posts on the DataSource, I'm going to create a very simple "to do" application.

To really illustrate the value of my custom DataSource, though, I'm not going to manually run methods and event handlers as I did previously. Instead, I'm going to stick to the default behaviors that the Kendo UI Grid provides. This will better illustrate how simple it was to provide the functionality that Kendo UI needs, when creating a custom DataSource.

(You can see the full code and the functioning demo app at this JSFiddle.)

As you can see, I didn't get the usability factor set quite right in this sample. I chose to leave the grid alone and not provide any custom usability enhancements, though. I wanted to illustrate how a few methods can be used to provide a completely new data transport for a Kendo UI DataSource, and show that it is possible, and fairly simple, to wrap a DataSource around a Backbone.Collection.

The First Steps Of A Long Journey

The code that I've shown here is far from complete and definitely not ready for production use. But it does illustrate some of the key concepts and shows that it is possible and some-what simple to do. It also paves the way for future work that I will be engaged in.

There is a lot of work left to do, though. Right now this only provides synchronization one-way: from the DataSource to the Backbone.Collection. But what happens when the Backbone.Collection is reset with new data? And what about persisting the data back to a server, through the Collection's "save" method? There's much work to be done, but this is a good first step.

About the Author
Derick Bailey is a Developer Advocate for Kendo UI, a developer, speaker, trainer, screen-caster and much more. He's been slinging code since the late 80’s and doing it professionally since the mid 90's. These days, Derick spends his time primarily writing javascript with back-end languages of all types, including Ruby, NodeJS, .NET and more. Derick blogs at DerickBailey.LosTechies.com, produces screencasts at WatchMeCode.net, tweets as @derickbailey and provides support and assistance for JavaScript, BackboneJS, MarionetteJS and much more around the web.

3 Comments

  1. 1 Paul Yoder 08 Feb 2013
    Thanks for the followup on my question about Backbone collections and Kendo data source!
  2. 2 Nir Hemed 11 Feb 2013
    Thank you for publishing this post. One thing that concerns me: in the above setup, how does Kendo DataSource determines its 'data' attribute?
  3. 3 Derick Bailey 11 Feb 2013
    Hi Nir Hemed,

    The `data` attribute is managed in the same manner as it would be for any transport - an XML API, JSON API, OData API, or in-memory array. I don't think any custom code has to be provided, to get the data array. In my quick tests, at least, I was able to see the correct array of data every time I looked for it.

Comment

  1. Click to add

  2. Click to add

  3. Click to add

  4.    
     
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
     
      
       
Blogs feed
Categories

  • Tutorials (26)
  • Release (33)
  • Browsers (7)
  • Extensions (3)
  • Tip of the Week (10)
  • Videos (5)
  • Concepts and Theory (13)
  • Misc. (25)
  • Framework Constructs (6)
  • Mobile (6)
  • UI Widgets (5)
  • Blogs (1)
Archive
  • 2013 May (8)
  • 2013 April (10)
  • 2013 March (9)
  • 2013 February (12)
  • 2013 January (10)
  • 2012 December (9)
  • 2012 November (11)
  • 2012 October (6)
  • 2012 September (7)
  • 2012 August (8)
  • 2012 July (10)
  • 2012 June (8)
  • 2012 May (10)
  • 2012 April (7)
  • 2012 March (13)
  • 2012 February (10)
  • 2012 January (6)
  • 2011 December (10)
  • 2011 November (4)
  • 2011 October (6)
  • 2011 September (5)
  • 2011 August (9)
Home Web Mobile DataViz Server Wrappers Whitepapers Surveys Chrome Icenium Contact Us

Kendo UI framework is developed by Telerik - a leading provider of UI components for web, desktop and mobile applications. Trusted by over 100,000 customers worldwide for our devotion to quality and industry-best technical support, Telerik helps professionals maximize their productivity and "deliver more than expected" every day.

kendoui - powered by html5, css3 & jquery
get social
  • Twitter
  • Facebook
  • Google plus
  • RSS
Privacy Policy | Branding Guidelines
Powered by Sitefinity CMS

Copyright © 2011 - 2013 Telerik Inc. All rights reserved.