我正在使用從localStorage
加載JSON數據的Angular directive
。異步調用函數的角度問題
這很容易用localStorage.getItem(id)
完成,但現在我試圖通過API調用(反過來從數據庫中提取)使其工作。
我有Angular工廠代碼工作,和http請求工作,但在指令代碼中有一個_handleAsyncLoad()
功能,這是扔我。換句話說,我試圖使用API層返回的serialized
對象的內置承諾。
前/我寫了新的匿名函數,_getItemFromAPI:
,但不確定是否需要使用_handleAsyncLoad:
函數。如果沒有,最好的方法是確保我的serialized
對象在返回之前填充數據。
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 = {
load: function (dashboardId) {
if (!this.storage) {
\t return null;
}
var serialized;
// fetch dashboard layout from storage
if (dashboardId != null && dashboardId != undefined) {
\t //serialized = this.storage.getItem(dashboardId); \t // OLDER, SIMPLER WAY
\t
\t serialized = this._getItemFromAPI($rootScope); \t // NEW WAY, PULL DATA VIA API ! \t
}
else {
\t // revert to original line; see dashboardOptions to main-controller
\t serialized = this.storage.getItem(this.id);
}
if (serialized) {
\t // check for promise
\t if (angular.isObject(serialized)) {
\t return this._handleAsyncLoad(serialized);
\t }
\t // otherwise handle synchronous load
\t return this._handleSyncLoad(serialized);
} else {
\t 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;
dashboardcontext.getDashboardImage(sid, userid, dashboardId).then(function (data) {
\t if (data.status == "FAIL") {
\t window.alert("Failed to retrieve dashboard. " + data.messages);
\t return false;
\t }
\t else {
\t return data;
\t }
});
return new Promise(function (resolve, reject) { });
},
_handleSyncLoad: function (serialized) {
var deserialized, result = [];
if (!serialized) {
\t return null;
}
if (this.stringify) {
\t try { // to deserialize the string
\t deserialized = JSON.parse(serialized);
\t } catch (e) {
\t // bad JSON, log a warning and return
\t $log.warn('Serialized dashboard state was malformed and could not be parsed: ', serialized);
\t return null;
\t }
}
else {
\t deserialized = serialized;
}
// Cache widgets
var savedWidgetDefs = deserialized.widgets;
return result;
},
_handleAsyncLoad: function (promise) {
var self = this;
var deferred = $q.defer();
promise.then(
\t // success
\t function (res) {
\t var result = self._handleSyncLoad(res);
\t if (result) {
\t \t deferred.resolve(result);
\t } else {
\t \t deferred.reject(result);
\t }
\t },
\t // failure
\t function (res) {
\t deferred.reject(res);
\t }
);
return deferred.promise;
}
};
return DashboardState;
}]);
databoardcontext
工廠代碼:
function getDashboardImage(sid, userid, id) {
var rageVars = $rootScope.rageSessionVars;
var url = "http://" + rageVars.domainName + ":" + rageVars.port + "/api/dashboards";
var sid = rageVars.sessionID;
var apiCall = "getDashboardImage";
var cssClass = "html";
var req = {
\t method: 'POST',
\t url: url,
\t headers: {
\t 'Content-Type': 'application/json', // application/x-www-form-urlencoded
\t },
\t data: { sid: sid, apiCall: apiCall, userid: userid, id: id }
};
var deferred = $q.defer();
deferred.notify("Retrieving dashboard image...");
$http(req).success(function (data, status, headers, config) {
\t deferred.resolve(data);
}).error(function (data, status, headers, config) {
\t console.log('Error retrieving dashboard ');
\t deferred.resolve();
});
return deferred.promise;
}
******** UPDATE 2015年9月8日下午2點55分:由於該誰提供答案,我發佈一些更新的代碼,以顯示現在的工作。 ********
angular.module('ui.dashboard')
.factory('DashboardState', ['$log', '$q', 'dashboardcontext', '$rootScope', function ($log, $q, dashboardcontext, $rootScope) {
var that = this; // *** CREATED NEW OBJECT HERE. REASSIGN BELOW IN load: FUNCTION ***
function DashboardState(storage, id, hash, widgetDefinitions, stringify) {
this.storage = storage;
this.id = id;
this.hash = hash;
this.widgetDefinitions = widgetDefinitions;
this.stringify = stringify;
}
DashboardState.prototype = {
save: function (widgets) {
/// SAVE CODE OMITTED FOR BREVITY
},
load: function (dashboardId) {
var useLocalStorage = false; // retrieve from localStorage or via API layer - 09/04/2015 BM:
var serialized;
if (useLocalStorage) { // retrieve dashboard layout from localStorage
\t if (!this.storage) {
\t return null;
\t }
\t if (dashboardId != null && dashboardId != undefined) {
\t serialized = this.storage.getItem(dashboardId);
\t // save the current dashboard id for next load
\t this.storage.setItem("defaultDashboardId", dashboardId);
\t }
}
else { \t
\t
\t if (dashboardId != null && dashboardId != undefined) {
\t this.storage.setItem("defaultDashboardId", dashboardId);
\t
\t that = this; \t // **** VERY IMPORTANT TO REASSIGN ***
\t
// *** RETURN IS VERY IMPORTANT HERE, AS WELL AS THE then() SECTION ***
\t return this._getItemFromAPI($rootScope).then(function (data) { \t \t
\t \t
\t \t return that._handleSyncLoad(data, true); // *** that. IS NOW AVAILABLE ON THE SCOPE ***
\t });
\t }
\t else {
\t // revert to original line; see dashboardOptions to main-controller
\t serialized = this.storage.getItem(this.id);
\t }
}
if (serialized) {
\t // check for promise
\t if (angular.isObject(serialized)) {
\t return this._handleAsyncLoad(serialized);
\t }
\t // otherwise handle synchronous load
\t return this._handleSyncLoad(serialized);
} else {
\t 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) {
\t return data.data[0];
});
},
_handleSyncLoad: function (serialized, isParsed) {
// @serialized {JSON} - parsed or unparsed Json object
// @isParsed {Boolean} - false if loaded from localStorage.getItem(); true if loaded from API, Json string already parsed.
var deserialized, result = [];
if (!serialized) {
\t return null;
}
if (isParsed) { // JSON already deserialzed in load: above; see _getItemFromAPI().then data object - 09/04/2015 BM:
\t deserialized = serialized;
}
else {
\t if (this.stringify) {
\t try { // to deserialize the string
\t \t deserialized = JSON.parse(serialized);
\t } catch (e) {
\t \t // bad JSON, log a warning and return
\t \t $log.warn('Serialized dashboard state was malformed and could not be parsed: ', serialized);
\t \t return null;
\t }
\t }
\t else {
\t deserialized = serialized;
\t }
}
// check hash against current hash
if (deserialized.hash !== this.hash) {
\t $log.info('Serialized dashboard from storage was stale (old hash: ' + deserialized.hash + ', new hash: ' + this.hash + ')');
\t this.storage.removeItem(this.id);
\t return null;
}
// Cache widgets
var savedWidgetDefs = deserialized.widgets;
// instantiate widgets from stored data
for (var i = 0; i < savedWidgetDefs.length; i++) {
\t // deserialized object
\t var savedWidgetDef = savedWidgetDefs[i];
\t // widget definition to use
\t var widgetDefinition = this.widgetDefinitions.getByName(savedWidgetDef.name);
\t // check for no widget
\t if (!widgetDefinition) {
\t // no widget definition found, remove and return false
\t $log.warn('Widget with name "' + savedWidgetDef.name + '" was not found in given widget definition objects');
\t continue;
\t }
\t // check widget-specific storageHash
\t if (widgetDefinition.hasOwnProperty('storageHash') && widgetDefinition.storageHash !== savedWidgetDef.storageHash) {
\t // widget definition was found, but storageHash was stale, removing storage
\t $log.info('Widget Definition Object with name "' + savedWidgetDef.name + '" was found ' +
\t \t 'but the storageHash property on the widget definition is different from that on the ' +
\t \t 'serialized widget loaded from storage. hash from storage: "' + savedWidgetDef.storageHash + '"' +
\t \t ', hash from WDO: "' + widgetDefinition.storageHash + '"');
\t continue;
\t }
\t // push instantiated widget to result array
\t result.push(savedWidgetDef);
}
return result;
},
_handleAsyncLoad: function (promise) {
// code same as original post...
}
};
return DashboardState;
}]);
@bob,它沒有被返回。它應該是'return dashboardcontext.getDashboardImage()...' –
我添加了'getDashboardImage'函數以供參考;但如果我理解正確,則表示Promise不是從'_getItemFromAPI()'返回的。 –
@bob,是的。我可以看到'getDashboardImage'返回一個承諾,因爲它後面跟着'.then',但是你還需要'返回''.then'的承諾 –