• .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

Creating A Kendo UI MVVM Widget

Tuesday, April 24, 2012 by Kendo UI Team Blog | Comments 15

Following up on last weeks post about creating custom DataBound Kendo UI Widgets, I wanted to cover how to make these widgets MVVM aware. The simple widget that I built in the last post is DataSource aware and can also be bound via declarative initialization. The declarative initialization comes along for free as part of the Kendo UI Framework when you create a plugin and define it’s options. For instance, you can set the DataSource of the simple repeater widget by setting its data-source property.

This works fine and dandy and is quite a handy way to bind widgets when you have several on a page. However we can improve this experience by allowing the user to encapsulate the initialization dependencies in their ViewModel, which is really a better home for them than just hanging out in a script block.

Hello MVVM

I suggest that you take a look at last week’s post before proceeding to familiarize yourself with what it takes to create a base widget and how to make that widget DataSource aware. From here on out, I am simply going to build on the code that I finished with in the last post.

Events

The first thing that we need to do is to define some events for our widget. Specifically, we need to expose the dataBinding event and the dataBound event. The dataBinding event will be what we call before we mutate the DOM with our widget. This gives MVVM a chance to traverse the fragment that we are about to mutate and unbind anything that is currently bound. The second event is the dataBound event, which allows MVVM to go back through the fragment and re-bind what is necessary. These events are exposed via the events object on the widget. These events are strings, so we define them as constants in the head of the widget as part of the pattern we use when developing all widgets.

Example

var DATABINDING = "dataBinding",
    DATABOUND = "dataBound",
    CHANGE = "change"    

var Repeater = kendo.ui.Widget.extend({

    init: function(element, options) {
        ...
    },
    options{
        ...
    },

    // events are used by other widgets / developers - API for other purposes
    // these events support MVVM bound items in the template. for loose coupling with MVVM.
    events: [
        // call before mutating DOM.
        // mvvm will traverse DOM, unbind any bound elements or widgets
        DATABINDING,
        // call after mutating DOM
        // traverses DOM and binds ALL THE THINGS
        DATABOUND
    ]
});

 

By exposing these as events for MVVM to listen to, we have loose coupling between our widget and the MVVM core engine. This means that if we don’t expose these events, MVVM simply won’t know about our widget’s lifecycle. This is a very good architecture as it ensures that your widget won’t break other MVVM bindings that it should have no knowledge of.

Items

MVVM will be expecting us to expose the DOM fragments from our widget which represent each row or each repeated data element. We should be returning the outermost element for MVVM to work with. While is varies, this is typically just this.element.children. Since each template item rendered is a DOM Fragment that is attached to the bound element, this is all we need. We can expose it for MVVM by making it available off of the items object.

Example

var DATABINDING = "dataBinding",
    DATABOUND = "dataBound",
    CHANGE = "change"    

var Repeater = kendo.ui.Widget.extend({

    init: function(element, options) {
        ...
    },
    options{
        ...
    },

    // events are used by other widgets / developers - API for other purposes
    // these events support MVVM bound items in the template. for loose coupling with MVVM.
    events: [
        // call before mutating DOM.
        // mvvm will traverse DOM, unbind any bound elements or widgets
        DATABINDING,
        // call after mutating DOM
        // traverses DOM and binds ALL THE THINGS
        DATABOUND
    ],

    // mvvm expects an array of dom elements that represent each item of the datasource.
    // should be the outermost element
    items: function() {
        return this.element.children();
    }
});

 

Changing The DataSource

Since it is possible to change the DataSource with MVVM, we need to implement the setDataSource function. MVVM will call this when the DataSource is set inside of a ViewModel. It’s a pretty simple implementation. We are simply going to set our internal DataSource reference equal to the one passed in by MVVM, and then rebuild the DataSource using the already defined _dataSource() function.

Example

        
// for supporting changing the datasource via MVVM
setDataSource: function(dataSource) {
    // set the internal datasource equal to the one passed in by MVVM
    this.options.dataSource = dataSource;
    // rebuild the datasource if necessary, or just reassign
    this._dataSource();
}

 

Tweak The _dataSource

We do need to make some small tweaks to our method which assigns or builds the DataSource. If you remember from the last post, the _dataSource method that we call in init does 3 things.

  1. Assign the DataSource, or build on from an array or configuration object.
  2. Read from the DataSource if autoBind is enabled and the DataSource has not yet been read from.
  3. Binds the change event on the DataSource to an internal refresh method that we handle manually.

Since we have already bound the change event on the DataSource possibly once, we need to make sure we unbind it if neccessary. If this is not done, the widget will retain a list of all the bindings and will execute the refresh function numerous times - which is not what we want. Also, MVVM will be listening to the internal _refreshHandler function which we have not yet defined. We simply need to point that internal _refreshHandler to our publicly exposes refresh method. First though, we need to check and see if there is an existing connection between the public refresh (which is bound to the change event on the DataSource) and the internal _refreshHandler. If there is, we need to remove just the binding to the change event. If there is no connection between our internal _refreshHandler and the public refresh function, we need to create it. This is done by the $.proxy jQuery method which simply calls the public refresh with the correct context, which is the widget itself. Finally, we rebind to the change event of the DataSource.

Example

        
_dataSource: function() {

    var that = this;

    // if the DataSource is defined and the _refreshHandler is wired up, unbind because
    // we need to rebuild the DataSource
    if ( that.dataSource && that._refreshHandler ) {
        that.dataSource.unbind(CHANGE, that._refreshHandler);
    }
    else {
        that._refreshHandler = $.proxy(that.refresh, that);
    }
 
    // returns the datasource OR creates one if using array or configuration object
    that.dataSource = kendo.data.DataSource.create(that.options.dataSource);

    // bind to the change event to refresh the widget
    that.dataSource.bind( CHANGE, that._refreshHandler );
 
    if (that.options.autoBind) {    
        that.dataSource.fetch();
    }
}

 

This can be a bit confusing if haven’t used the proxy jQuery function before, but all it’s doing is saying that when the _refreshHandler is called, it should execute the public refresh widget function and inside that refresh function, this will be a reference to the widget itself, and not something else (like window for instance). Due to the fact that the keyword this is always changing in JavaScript, this is just a good way to ensure that the scope is correct when the refresh function executes.

We Are Almost Done!

Finally, we simply need to trigger the dataBinding and dataBound events. We do this in the public refresh and remember, dataBinding happens before we mutate the DOM and dataBound happens directly after.

Example

        
refresh: function() {
    var that = this,
        view = that.dataSource.view(),
        html = kendo.render(that.template, view);

    // trigger the dataBinding event
    that.trigger(DATABINDING);

    // mutate the DOM (AKA build the widget UI)
    that.element.html(html);

    // trigger the dataBound event
    that.trigger(DATABOUND);
}

 

And with that, we have now fully enabled MVVM in our widget. This means we can now define the widget like so:

Example

	
<div data-role="repeater" data-bind="source: dataSource">
<script>
    var viewModel = kendo.observable({
        dataSource:  new kendo.data.DataSource({
                        transport: {
                            read: "Customers/Orders",
                            dataType: "json"
                        }
                    })  
    })

    kendo.bind(document.body.children, viewModel);
</script>

 

Notice that the widget is now bound to the dataSource variable inside of the ViewModel via data-bind. This means that if we add an item client side to the DataSource, our widget will reflect the change immediately, without us having to re-render anything.

I have attached a fiddle below for demonstration. Notice that when you add an item to the DataSource, it is immediately reflected in the Repeater widget. Very nice.

That’s A Wrap

That’s a wrap on how to create a custom Kendo UI Widget from scratch. For reference, here are the other two posts that you might want to refer back to to get a complete understanding of what the widget lifecycle is, and how to make a widget DataSource aware.

  • Creating A Custom Kendo UI Plugins
  • Creating A Custom DataSource Aware Kendo UI Plugin

Download Kendo UI today and get started building your own widgets with the powerful core that we have exposed for you to use as well.

About the Author
Burke Holland is a web developer living in Nashville, TN. He enjoys working with and meeting developers who are building mobile apps with jQuery / HTML5 and loves to hack on social API's. Burke works for Telerik as a Developer Evangelist focusing on Kendo UI. Burke is @burkeholland on Twitter.

15 Comments

  1. 1 Jacques 25 Apr 2012
    Burke,

    Those blog posts on developing custom Kendo widgets are awesome as they really reveal the building blocs of a client application design and put us on the path to commit to Kendo UI to redesign our applications although I am still struggling with complex data structures.

    The _dataSource function is obviously very specific to the Kendo UI DataSource. But what if you just want to bind to a viewModel? How would you write the _viewModel function?

    To start with, I cannot find a kendo.data.ViewModel.create function in the sources.
  2. 2 Jacques 25 Apr 2012
    To explain more, the proof of concept I am working on includes a basic property grid (object inspector) designed as per kendo UI MVVM principles....
  3. 3 Veli 25 Apr 2012
    Burke,

    Your series rocks! Just a small comment on the _dataSource() method. Shouldn't you be unbinding the CHANGE event from the old dataSource before building the new one?

    _dataSource: function() {
        var that = this;
        // unbind the CHANGE handler from the old dataSource   
        // before building the new one
        if (that.dataSource && that._refreshHandler) {
            that.dataSource.unbind(CHANGE, that._refreshHandler);
        }
        else {
            that._refreshHandler = $.proxy(that.refresh, that);
        }
         
        that.dataSource = kendo.data.DataSource.create(that.options.dataSource);
        that.dataSource.bind( CHANGE, that._refreshHandler );
     
        if (that.options.autoBind) {   
            that.dataSource.fetch();
        }
    }
  4. 4 Burke 25 Apr 2012
    @Jacques

    I'm not sure I follow.  Can you email me directly - burke@kendoui.com?  If I can see your code, it will be easier for me to help you figure out how to properly implement the functionality.
  5. 5 Burke 25 Apr 2012
    @Veli

    Yes! I believe you are correct.  The old DataSource needs to be unbound (if it exists) before the new one is created.  I have updated the post to show this.  

    Nice catch!
  6. 6 Jacques 26 Apr 2012
    Burke,

    Sorry, my comment was confusing and maybe I should have refered to a kendo.observable rather than a viewModel. I would like do bind an observable (object, array), not a dataSource. 

    I am trying to put Kendo UI MVVM through its paces to understand the design implications and limitations. One prototype we have in progress includes:
    1) a custom widget wrapping a Raphael.js canvas (when you click on the drwaing surface you draw a rectangle or a circle depending on the value of an option group);
    2) a kendo UI grid which lists all the shapes on the canvas and allows the selection of a shape (no selection at this stage on the drawing surface).
    3) a custom widget which is a very basic property grid (strings and numbers only) to edit the selected shape's properties (x, y, stroke, fill, etc.). This property grid is work in progress.

    Thanks to your series of posts regarding custom widgets I got it working (not polished around the edges) with a dataSource wrapping an array of shapes as long as all the shapes where all identical because identical shapes are defined by the same attributes, i.e.  x, y, w, h for rectangles and other attributes like stroke and fill.

    Then I have added circles, defined by cx, cy, r (center and radius). I had to replace the dataSource with an observable array of shapes and things got more complicated...

    Thank you for offering to review the code. So that the community can benefit I'll try to trim down the code to something we can fiddle. In the meantime, maybe this is more clear and you can put me on the right track.
  7. 7 Burke 30 Apr 2012
    @Jacques

    You should be able to use an observable array in your view model the same way that you do a DataSource.  All the things in a view model are observable.  It sounds as if the structure of your data is changing per the type of shape you would need to draw.

    My offer stands to review the code and try to help.  Unfortunately, I can't see anything from your description that stands out to me as a quick win.

    Feel free to pop it up in GitHub or a Fiddle and I'll do what I can to help.
  8. 8 Gabriel Smith 01 May 2012
    nice post
  9. 9 ah 07 Jun 2012
    stop changing this to that. It makes your event code confusing beyond belief. you are ridiculous..
  10. 10 RodEsp 18 Jul 2012
    Hey Burke,

    First of all thanks for these awesome posts.
    Second, I'm trying to create a widget for Kendo's mobile framework but I'm having trouble initializing it.

    What do I have to do differently other than pluging in the widget to the kendo.mobile.ui instead of the kendo.ui?
    Do I have to include kendo.all in my mobile project in order to be able to add custom widgets?

    Thanks.
  11. 11 RodEsp 24 Jul 2012
    Nevermind. Just found this in the docs:

    Important: Kendo UI Mobile is not included in the default list of initialized namespaces. You can initialize it explicitly by running kendo.bind(element, viewModel, kendo.mobile.ui); 
  12. 12 Jonathan Perl 31 Jul 2012
    Hi Burke,

    First thank you for this post. I have tried to read through the source code of other widgets to figure out how to do this, but so far to no avail.

    I would like to create a custom widget which has a source property that can be bound to by a single ObservableObject (not a DataSource object).

    Whenever the object changes, the widget would dynamically construct different widgets inside of it. Each of those widgets would be bound to properties on the ObservableObject.

    If you have any guidance that would be greatly appreciated. Or if you could do a blog post of this more complex MVVM problem that would be event better!
  13. 13 Jonathan Perl 06 Aug 2012
    I have been able to do this by creating a custom binder which triggers a render function in my custom widget.

    I am not sure if it is best practice, but it works.
  14. 14 Steve 29 Nov 2012
    Hi Burke, could you further explain when the setDataSource function is called via MVVM?

    I have removed this function from my custom widget and everything still works?!
  15. 15 don 26 Mar 2013
    Is it possible that the change that is made ( like an Item added by the website visitor) remains saved .... so another person with different ip addresse can see this change ?
    if yes how to add this change to data that should be visualized?
    for example : if I need some Items to be rated and then those values are copyed in a data bank?
    Thanks in Advance :)

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 (7)
  • 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.