• Jump To … +
    modules/Behavior.js modules/Cell.js modules/Collection.js modules/Events.js modules/FormModel.js modules/FormView.js modules/ListView.js modules/Model.js modules/NestedCell.js modules/NestedModel.js modules/Router.js modules/ServiceCell.js modules/View.js modules/behaviors/DataBehavior.js modules/configure.js modules/handlebarsUtils.js modules/history.js modules/mixins/cacheMixin.js modules/mixins/cellMixin.js modules/mixins/loadingMixin.js modules/mixins/modelMixin.js modules/mixins/pollingMixin.js modules/registry.js modules/stickitUtils.js modules/templateRenderer.js modules/torso.js modules/validation.js
  • loadingMixin.js

  • ¶
    (function(root, factory) {
      if (typeof define === 'function' && define.amd) {
        define(['backbone'], factory);
      } else if (typeof exports === 'object') {
        module.exports = factory(require('backbone'));
      } else {
        root.Torso = root.Torso || {};
        root.Torso.Mixins = root.Torso.Mixins || {};
        root.Torso.Mixins.loading = factory(root.Backbone);
      }
    }(this, function(Backbone) {
    
      var $ = Backbone.$;
    
      /**
       * Loading logic.
       *
       * @mixin loadingMixin
       *
       * @author kent.willis@vecna.com
       *
       * @see <a href="../annotated/modules/mixins/loadingMixin.html">loadingMixin Annotated Source</a>
       */
      var loadingMixin = function(base) {
    
        return /** @lends loadingMixin */ {
          /**
           * Adds the loading mixin
           * @param {Object} args the arguments to the base constructor method
           */
          constructor: function(args) {
            base.call(this, args);
            this.loadedOnceDeferred = new $.Deferred();
            this.loadedOnce = false;
            this.loadingCount = 0;
  • ¶

    Loading is a convenience flag that is the equivalent of loadingCount > 0

            this.loading = false;
          },
    
          /**
           * @returns {boolean} true if this model/collection has ever loaded from a fetch call
           */
          hasLoadedOnce: function() {
            return this.loadedOnce;
          },
    
          /**
           * @returns {boolean} true if this model/collection is currently loading new values from the server
           */
          isLoading: function() {
            return this.loading;
          },
    
          /**
           * @returns {Promise} a promise that will resolve when the model/collection has loaded for the first time
           */
          getLoadedOncePromise: function() {
            return this.loadedOnceDeferred.promise();
          },
    
          /**
           * Wraps the base fetch in a wrapper that manages loaded states
           * @param {Object} options - the object to hold the options needed by the base fetch method
           * @returns {Promise} The loadWrapper promise
           */
          fetch: function(options) {
            return this.__loadWrapper(base.prototype.fetch, options);
          },
    
          /**
           * Base load function that will trigger a "load-begin" and a "load-complete" as
           * the fetch happens. Use this method to wrap any method that returns a promise in loading events
           *
           * @private
           * @param {Function} fetchMethod - the method to invoke a fetch
           * @param {Object} options - the object to hold the options needed by the fetchMethod
           * @returns {Promise} a promise when the fetch method has completed and the events have been triggered
           */
          __loadWrapper: function(fetchMethod, options) {
            var object = this;
            this.loadingCount++;
            this.loading = true;
            this.trigger('load-begin');
            return $.when(fetchMethod.call(object, options)).always(function() {
              if (!object.loadedOnce) {
                object.loadedOnce = true;
                object.loadedOnceDeferred.resolve();
              }
              object.loadingCount--;
              if (object.loadingCount <= 0) {
                object.loadingCount = 0; // prevent going negative.
                object.loading = false;
              }
            }).done(function(data, textStatus, jqXHR) {
              object.trigger('load-complete', {success: true, data: data, textStatus: textStatus, jqXHR: jqXHR});
            }).fail(function(jqXHR, textStatus, errorThrown) {
              object.trigger('load-complete', {success: false, jqXHR: jqXHR, textStatus: textStatus, errorThrown: errorThrown});
            });
          }
        };
      };
    
      return loadingMixin;
    }));