我的Angular工厂代码中的范围问题

时间:2015-09-08 15:36:21

标签: angularjs angularjs-scope

我有一个名为'DashboardState'的Angular工厂,我目前正在修改它以通过我的dashboardcontext Angular服务层处理API调用。

目前,我的所有widget数据都会持久保存到localStorage对象;但是,我现在正在进入一个新的c#API层,它将布局小部件设置到永久存储器(即本例中的Sql Server数据库)。

我的主要问题是在promise函数的return this._getItemFromAPI($rootScope).then处返回load:时会发生什么。

load:部分中,this是一个有效的对象,其中包含方法;但是,在.then部分内,我突然无法访问this.

这对我来说是一个问题,因为我不能再打电话给this._handleSyncLoad了。正如您所看到的,我通过分配var handleSync = this._handleSyncLoad;尝试了一次黑客攻击,但是它没有解决范围问题。:

  if (dashboardId != null && dashboardId != undefined) {

                  this.storage.setItem("defaultDashboardId", dashboardId);

                  var handleSync = this._handleSyncLoad;
                  return this._getItemFromAPI($rootScope).then(function (data) {                           
                      // save current current dashboard id for next time - 06/11/2015 BM:      

                      return handleSync(data, true);    

                   });                      
              }

以下是'DashboardState'的完整列表:

angular.module('ui.dashboard')
.factory('DashboardState', ['$log', '$q', 'dashboardcontext', '$rootScope', function ($log, $q, dashboardcontext, $rootScope) {
function DashboardState(storage, id, hash, widgetDefinitions, stringify) {
  this.storage = storage;
  this.id = id;
  this.hash = hash;
  this.widgetDefinitions = widgetDefinitions;
  this.stringify = stringify;
}

DashboardState.prototype = {
  /**
   * Takes array of widget instance objects, serializes, and saves state.
   * 
   * @param  {Array} widgets  scope.widgets from dashboard directive
   * @return {Boolean}        true on success, false on failure
   */
 save: function (widgets) {             
      // CODE OMITTED FOR SAVE FUNCTION
      return true;
  },                   
 load: function (dashboardId) {        // sent in from navigation-controller call 

      var useLocalStorage = false;     // retrieve from localStorage or via API layer

      var serialized;

      if (useLocalStorage) {           // retrieve dashboard layout from localStorage                  
	      // COME CODE OMITTED FOR BREVITY
	      serialized = this.storage.getItem(dashboardId);                  
	  }
      }
      else {                  

	  // FETCH DASHBOARD HERE !! 
	  if (dashboardId != null && dashboardId != undefined) {

	      // *** "this" is available on the scope at this point ***
	      this.storage.setItem("defaultDashboardId", dashboardId);

	      var handleSync = this._handleSyncLoad;
	      return this._getItemFromAPI($rootScope).then(function (data) {                                                         
		  // *** "this" IS NO LONGER AVAILABLE ON THE SCOPE - i.e. I can no longer call this._handleSyncLoad from here ***
		  return handleSync(data, true);    

	       });                      
	  }
	  else {
	      // revert to original line; see dashboardOptions to main-controller
	      serialized = this.storage.getItem(this.id);
	  }                  
      }

      if (serialized) {
	  // check for promise
	  if (angular.isObject(serialized)) {    // && angular.isFunction(serialized.then)) {    // modifed line 09/04/2015 BM:
	      return this._handleAsyncLoad(serialized);
	  }
	  // otherwise handle synchronous load
	  return this._handleSyncLoad(serialized);
      } else {
	  return null;
      }

  },         

  _getItemFromAPI: function ($rootscope) {
      // SERVER-SIDE API CALL TO PERSIST DASHBOARD TO STORAGE - 09/03/2015 BM:
      var sid = $rootScope.rageSessionVars.sessionID;
      var userid = $rootScope.rageSessionVars.userID;
      var dashboardId = this.id;

      return dashboardcontext.getDashboardImage(sid, userid, dashboardId).then(function (data) {
	  if (data.status == "FAIL") {
	      window.alert("Failed to retrieve dashboard. " + data.messages);
	      return false;
	  }
	  else {                      
	      return data;
	  }
      });            
  },

  _handleSyncLoad: function (serialized, isParsed) {


      // **** MUST HANDLE THE isParsed PARAM; serialized object is alredy parsed ****

      var deserialized, result = [];

      if (!serialized) {
	  return null;
      }

      if (this == undefined) {    // problem if coming from .then of this._getItemFromAPI in load:  - 09/04/2015 BM:

	  deserialized = JSON.parse(serialized);

      }
      else {
	  if (this.stringify) {
	      try { // to deserialize the string

		  deserialized = JSON.parse(serialized);

	      } catch (e) {

		  // bad JSON, log a warning and return
		  $log.warn('Serialized dashboard state was malformed and could not be parsed: ', serialized);
		  return null;

	      }
	  }
	  else {
	      deserialized = serialized;
	  }
      }

      // check hash against current hash
      if (deserialized.hash !== this.hash) {

	  $log.info('Serialized dashboard from storage was stale (old hash: ' + deserialized.hash + ', new hash: ' + this.hash + ')');
	  this.storage.removeItem(this.id);
	  return null;

      }

      // Cache widgets
      var savedWidgetDefs = deserialized.widgets;

      // instantiate widgets from stored data
      for (var i = 0; i < savedWidgetDefs.length; i++) {

	  // deserialized object
	  var savedWidgetDef = savedWidgetDefs[i];

	  // widget definition to use
	  var widgetDefinition = this.widgetDefinitions.getByName(savedWidgetDef.name);

	  // check for no widget
	  if (!widgetDefinition) {
	      // no widget definition found, remove and return false
	      $log.warn('Widget with name "' + savedWidgetDef.name + '" was not found in given widget definition objects');
	      continue;
	  }

	  // check widget-specific storageHash
	  if (widgetDefinition.hasOwnProperty('storageHash') && widgetDefinition.storageHash !== savedWidgetDef.storageHash) {
	      // widget definition was found, but storageHash was stale, removing storage
	      $log.info('Widget Definition Object with name "' + savedWidgetDef.name + '" was found ' +
		'but the storageHash property on the widget definition is different from that on the ' +
		'serialized widget loaded from storage. hash from storage: "' + savedWidgetDef.storageHash + '"' +
		', hash from WDO: "' + widgetDefinition.storageHash + '"');
	      continue;
	  }

	  // push instantiated widget to result array
	  result.push(savedWidgetDef);
      }

      return result;
  },

  _handleAsyncLoad: function (promise) {
      var self = this;
      var deferred = $q.defer();
      promise.then(
	// success
	function (res) {
	    var result = self._handleSyncLoad(res);
	    if (result) {
		deferred.resolve(result);
	    } else {
		deferred.reject(result);
	    }
	},
	// failure
	function (res) {
	    deferred.reject(res);
	}
      );

      return deferred.promise;
  }

};

return DashboardState;
}]);

非常感谢您的建议。

的问候, 鲍勃

1 个答案:

答案 0 :(得分:1)

this总是引用当前函数,因此如果嵌套函数定义,则必须以某种方式解决它。

这是一个可以解决您问题的典型模式:

function someFunction() {
  var that = this;
  doSomething().then(function() {
    // 'that' is your 'this'
  });
}