我正在使用Angular directive
加载来自localStorage
的JSON数据。
使用localStorage.getItem(id)
可以轻松完成此操作,但现在我正在尝试通过API调用使其工作(后者又从数据库中提取)。
我有Angular工厂代码正常工作,http请求正常工作,但在指令代码中有一个_handleAsyncLoad()
函数,它正在抛弃我。换句话说,我正在尝试使用从API层返回的serialized
对象的内置承诺。
ex /我已经编写了新的匿名函数_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) {
return null;
}
var serialized;
// fetch dashboard layout from storage
if (dashboardId != null && dashboardId != undefined) {
//serialized = this.storage.getItem(dashboardId); // OLDER, SIMPLER WAY
serialized = this._getItemFromAPI($rootScope); // NEW WAY, PULL DATA VIA API !
}
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)) {
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;
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;
}
});
return new Promise(function (resolve, reject) { });
},
_handleSyncLoad: function (serialized) {
var deserialized, result = [];
if (!serialized) {
return null;
}
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;
}
// Cache widgets
var savedWidgetDefs = deserialized.widgets;
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;
}]);
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 = {
method: 'POST',
url: url,
headers: {
'Content-Type': 'application/json', // application/x-www-form-urlencoded
},
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) {
deferred.resolve(data);
}).error(function (data, status, headers, config) {
console.log('Error retrieving dashboard ');
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
if (!this.storage) {
return null;
}
if (dashboardId != null && dashboardId != undefined) {
serialized = this.storage.getItem(dashboardId);
// save the current dashboard id for next load
this.storage.setItem("defaultDashboardId", dashboardId);
}
}
else {
if (dashboardId != null && dashboardId != undefined) {
this.storage.setItem("defaultDashboardId", dashboardId);
that = this; // **** VERY IMPORTANT TO REASSIGN ***
// *** RETURN IS VERY IMPORTANT HERE, AS WELL AS THE then() SECTION ***
return this._getItemFromAPI($rootScope).then(function (data) {
return that._handleSyncLoad(data, true); // *** that. IS NOW AVAILABLE ON THE SCOPE ***
});
}
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)) {
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) {
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) {
return null;
}
if (isParsed) { // JSON already deserialzed in load: above; see _getItemFromAPI().then data object - 09/04/2015 BM:
deserialized = 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) {
// code same as original post...
}
};
return DashboardState;
}]);
答案 0 :(得分:2)
只要您进行异步操作,您就应该使公共API异步,即使在某些情况下或大多数情况下它都是同步的。然后,用户的API是一致的。
而不是&#34;检查承诺&#34;,将同步调用转换为承诺。
您的load
功能可以简化为以下内容(为了简洁起见,我会留下一些细节,但您应该了解更广泛的概念):
load: function(dashboardId) {
if (isSync()){
// sync
var data = this.storage.getItem(dashboardId);
// wrap in a promise
return $q.resolve(_handleSyncLoad(data));
} else {
// async
// return the promise generated by _getItemFromAPI().then()
return _getItemFromAPI().then(function(data){
return _handleSyncLoad(data);
});
}
}
请注意,我假设_getItemFromAPI()
返回一个承诺(在您的情况下它不会),所以它会如下所示:
function _getItemFromAPI(){
// ...
// this "return" is important! it returns the promise generated by $http
return $http({...}).then(function(response){
return response.data;
})
}
这使load
的使用保持一致,无论是同步还是异步:
dashboardSvc.load(444).then(function(dashboardData){
$scope.dashboard = dashboardData;
});