data source, add() + sync() + promises ?

2 posts, 0 answers
  1. Jeroen
    Jeroen avatar
    4 posts
    Member since:
    Jun 2012

    Posted 12 Nov 2012 Link to this post

    I'm creating a single page app and I run into some trouble. It's basically very simple. When I try to persist a new model (model A) it want to use a property of this model (model A.id) in the persistance of another model (model B). The property 'id' (model A.id) is supplied by the back-end.

    If I use the following sequence;

    var A = dataSource.add({ dataObjectA });
    dataSource.sync();
     
    var dataObjectB = { 'aId' : A.id, 'otherData': [] };
    var B = otherDataSource.add({ dataObjectB });
    dataSource.sync();

    then the property A.id will be present AFTER the sync() call on the data source. The a-synchronous nature of these calls will lead to the problem that when the call is being made to the otherDataSource.add method the property A.id is not yet set.

    After an extensive search I thought of a solution using promises. Since I don't know how to implement these I looked at the source of the data source component. That is when I discovered that the data source already has some sort of promises built in. Would it be possible to supply me (and all readers of this forum) with an example of how to use the promises?

    This problem is giving me massive headaches and I've been stuck with the development of my app for quite some time so some help would be very, very, very much appreciated! :) 
  2. Jeroen
    Jeroen avatar
    4 posts
    Member since:
    Jun 2012

    Posted 13 Nov 2012 Link to this post

    After being a bit disappointed about the lack of reactions to my question, I figured it out myself.

    Looking at the source of the datasource in kendo.web.js, I already saw that jQuery's deferred was being used by the sync() method of the datasource. The only thing missing is a return value from the sync() method. That's why I decided to overwrite the sync() method with one of my own. This own implementation returns the deferred.

    kendo.data.DataSource.prototype.sync = function() {
     
        var that = this,
            idx,
            length,
            created = [],
            updated = [],
            destroyed = that._destroyed,
            data = that._flatData(that._data);
     
        if (!that.reader.model) {
            return;
        }
     
        for (idx = 0, length = data.length; idx < length; idx++) {
            if (data[idx].isNew()) {
                created.push(data[idx]);
            } else if (data[idx].dirty) {
                updated.push(data[idx]);
            }
        }
     
        var promises = that._send("create", created);
     
        promises.push.apply(promises ,that._send("update", updated));
        promises.push.apply(promises ,that._send("destroy", destroyed));
     
        $.when.apply(null, promises)
            .then(function() {
                var idx,
                length;
     
                for (idx = 0, length = arguments.length; idx < length; idx++){
                    that._accept(arguments[idx]);
                }
     
                that._change();
                 
            });
         
        return promises[0];
             
    }

    For convenience I added another method to the kendo datasource object which simplifies the persistence of newly creates models with the back-end.

    kendo.data.DataSource.prototype.create = function(data) {
     
        this.add(data);
         
        return this.sync();
         
    }

    So how would I be using this in my view?

    The return value of the sync() method is a jQuery deferred (http://api.jquery.com/category/deferred-object/). This has a method which will be executed when the promis(es) have been executed. this method is called; done(). I implement the creation of a new record (and it like this:

    var location = null;
     
    var deferred = locationDatasource.create(locationData);
     
    deferred.done(function(data){
         
        // the newly created and persisted model is available...
        location = data.models[0];
         
        // ... and, hey! the property id which has been added by the persistence with the database (back-end)
        // is available now... (and now I can do... whatever with it! :)
        console.log(location.id);
    });
     
    // ... since this code normally executes, when it arrives overhere the property id still isn't available :'(
    console.log(location.id);
    Naturally the other methods of the deferred can also be implemented to address all other possible scenario's.

    Hopefully this is helpful/a great timesaver for other developers since I spend almost 2 days figuring it out... :'(

    Cheers!



     
Back to Top