dojo/store/Observable.js

  • Provides:

    • dojo.store.Observable
  • dojo.store.Observable

    • type
      Function
    • parameters:
      • store: (typeof )
    • source: [view]
       var queryUpdaters = [], revision = 0;
       // a Comet driven store could directly call notify to notify observers when data has
       // changed on the backend
       store.notify = function(object, existingId){
        revision++;
        var updaters = queryUpdaters.slice();
        for(var i = 0, l = updaters.length; i < l; i++){
         updaters[i](object, existingId);
        }
       };
       var originalQuery = store.query;
       store.query = function(query, options){
        options = options || {};
        var results = originalQuery.apply(this, arguments);
        if(results && results.forEach){
         var nonPagedOptions = dojo.mixin({}, options);
         delete nonPagedOptions.start;
         delete nonPagedOptions.count;


         var queryExecutor = store.queryEngine && store.queryEngine(query, nonPagedOptions);
         var queryRevision = revision;
         var listeners = [], queryUpdater;
         results.observe = function(listener, includeObjectUpdates){
          if(listeners.push(listener) == 1){
           // first listener was added, create the query checker and updater
           queryUpdaters.push(queryUpdater = function(changed, existingId){
            dojo.when(results, function(resultsArray){
             var atEnd = resultsArray.length != options.count;
             var i;
             if(++queryRevision != revision){
              throw new Error("Query is out of date, you must observe() the query prior to any data modifications");
             }
             var removedObject, removedFrom = -1, insertedInto = -1;
             if(existingId){
              // remove the old one
              for(i = 0, l = resultsArray.length; i < l; i++){
               var object = resultsArray[i];
               if(store.getIdentity(object) == existingId){
                removedObject = object;
                removedFrom = i;
                if(queryExecutor || !changed){// if it was changed and we don't have a queryExecutor, we shouldn't remove it because updated objects would be eliminated
                 resultsArray.splice(i, 1);
                }
                break;
               }
              }
             }
             if(queryExecutor){
              // add the new one
              if(changed &&
                // if a matches function exists, use that (probably more efficient)
                (queryExecutor.matches ? queryExecutor.matches(changed) : queryExecutor([changed]).length)){


               if(removedFrom > -1){
                // put back in the original slot so it doesn't move unless it needs to (relying on a stable sort below)
                resultsArray.splice(removedFrom, 0, changed);
               }else{
                resultsArray.push(changed);
               }
               insertedInto = dojo.indexOf(queryExecutor(resultsArray), changed);
               if((options.start && insertedInto == 0) ||
                (!atEnd && insertedInto == resultsArray.length -1)){
                // if it is at the end of the page, assume it goes into the prev or next page
                insertedInto = -1;
               }
              }
             }else if(changed){
              // we don't have a queryEngine, so we can't provide any information
              // about where it was inserted, but we can at least indicate a new object
              insertedInto = removedFrom >= 0 ? removedFrom : (store.defaultIndex || 0);
             }
             if((removedFrom > -1 || insertedInto > -1) &&
               (includeObjectUpdates || !queryExecutor || (removedFrom != insertedInto))){
              var copyListeners = listeners.slice();
              for(i = 0;listener = copyListeners[i]; i++){
               listener(changed || removedObject, removedFrom, insertedInto);
              }
             }
            });
           });
          }
          return {
           cancel: function(){
            // remove this listener
            listeners.splice(dojo.indexOf(listeners, listener), 1);
            if(!listeners.length){
             // no more listeners, remove the query updater too
             queryUpdaters.splice(dojo.indexOf(queryUpdaters, queryUpdater), 1);
            }
           }
          };
         };
        }
        return results;
       };
       var inMethod;
       function whenFinished(method, action){
        var original = store[method];
        if(original){
         store[method] = function(value){
          if(inMethod){
           // if one method calls another (like add() calling put()) we don't want two events
           return original.apply(this, arguments);
          }
          inMethod = true;
          try{
           return dojo.when(original.apply(this, arguments), function(results){
            action((typeof results == "object" && results) || value);
            return results;
           });
          }finally{
           inMethod = false;
          }
         };
        }
       }
       // monitor for updates by listening to these methods
       whenFinished("put", function(object){
        store.notify(object, store.getIdentity(object));
       });
       whenFinished("add", function(object){
        store.notify(object);
       });
       whenFinished("remove", function(id){
        store.notify(undefined, id);
       });


       return store;
    • summary
      The Observable store wrapper takes a store and sets an observe method on query()
      results that can be used to monitor results for changes.
    • description
      Observable wraps an existing store so that notifications can be made when a query
      is performed.
    • example
      Create a Memory store that returns an observable query, and then log some
      information about that query.
      
      	var store = dojo.store.Observable(new dojo.store.Memory({
      		data: [
      			{id: 1, name: "one", prime: false},
      			{id: 2, name: "two", even: true, prime: true},
      			{id: 3, name: "three", prime: true},
      			{id: 4, name: "four", even: true, prime: false},
      			{id: 5, name: "five", prime: true}
      		]
      	}));
      	var changes = [], results = store.query({ prime: true });
      	var observer = results.observe(function(object, previousIndex, newIndex){
      		changes.push({previousIndex:previousIndex, newIndex:newIndex, object:object});
      	});
      
      See the Observable tests for more information.
  • dojo.store

    • type
      Object
    • summary
  • dojo

    • type
      Object
    • summary