最近,通过iframe沙箱模式,可以在google apps脚本中使用angularjs。
当我尝试与服务器(gapps电子表格)通信并接收异步数据时,我的问题出现了。
从服务器接收数据的实现是使用具有回调函数的函数,如下所示:
google.script.run.withSuccessHandler(dataGatheringFunction).getServerData();
getServerData()
将是一个驻留在服务器端的函数,它会返回一些数据,通常来自随附的电子表格。我的问题是如何在AngularJS的参数中使用回调函数。典型的$http
函数可以放在提供程序中,范围值可以在then.()
返回后填充。我也可以调用$q
。但是,我如何处理谷歌回调的必要性?
这是我到目前为止所搞乱的简化版本:
app.factory("myFactory", function($q){
function ssData(){
var TssData = function(z){
return z;
}
google.script.run.withSuccessHandler(TssData).getServerData();
var deferred = $q.defer();
var d = deferred.resolve(TssData)
console.log("DP: " + deferred.promise);
return deferred.promise;
}
return ssData();
})
然后在控制器中解析类似这样的服务器调用: myFactory.then( 在这里设置一些带有返回数据的变量 )
我的问题很简单 - 如何处理提供程序中的回调函数?
脚本不会抛出任何错误,但不会从服务器返回数据。我可以使用旧的$ timeout技巧来检索数据,但应该有更好的方法。
答案 0 :(得分:4)
您只需要 $ apply 来自服务器功能的输出:
google.script.run.withSuccessHandler(function(data) {
$scope.$apply(function () {
$scope.data = data;
});
}).withFailureHandler(errorHandler).serverFunction();
答案 1 :(得分:4)
也许确保在AngularJS摘要周期中自动注册google.script.run
回调的最优雅的解决方案是使用$q
构造函数来宣传google回调。所以,使用上面的例子:
app.factory('myFactory', ['$q', function ($q){
return {ssData: ssData};
function ssData(){
var TssData = function(z){
return z;
};
var NoData = function(error) {
// Error Handling Here
};
return $q(function(resolve, reject) {
google.script.run
.withSuccessHandler(resolve)
.withFailureHandler(reject)
.getServerData();
}).then(TssData).catch(NoData);
}
}]);
然后在您的控制器中,您可以拨打myFactory.ssData()
由于我不确切知道TssData
正在做什么,所以我将其包含在此处,但请注意,这只会在此上下文中返回另一个承诺,您仍需要在控制器中处理:
myFactory.ssData().then(function(response) {
// Set data to the scope or whatever you want
});
或者,如果正在进行某种数据转换,您可以通过将TssData
添加到工厂的函数中来公开它。如果它真的只是返回响应,您可以重构代码并省略TssData
和NoData
并完全在控制器中处理承诺:
app.factory('myFactory', ['$q', function ($q){
return {ssData: ssData};
function ssData(){
return $q(function(resolve, reject) {
google.script.run
.withSuccessHandler(resolve)
.withFailureHandler(reject)
.getServerData();
});
}
}]);
app.controller('myController', ['myFactory', function(myFactory) {
var vm = this;
myFactory.ssData()
.then(function(response) {
vm.myData = response;
}).catch(function(error) {
// Handle Any Errors
});
}]);
关于承诺的优秀文章(以Angular和其他方式)在这里:http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html
答案 2 :(得分:3)
This guy似乎将GSheet中的数据非常愉快地提取到角度,而不必做任何花哨的事情。
function gotData(res) {
$scope.validUser = res.validUser;
var data = angular.copy(res.data), obj, i=0;
Object.keys(data).forEach(function(sh) {
obj = {title: sh, checked: {}, showFilters: false, search: {}, sort: {index: 0, reverse: false}, currentPage: 0, checkedAll: true, showBtns: true, searchAll: ''};
obj.heading = data[sh].shift();
obj.list = data[sh];
obj.heading.forEach(function(s,i) {
obj.checked[i] = true;
});
$scope.sheets.push(obj);
});
$scope.sheets.sort(function(a,b) {
return a.title > b.title ? 1 : -1;
});
$scope.gotData = true;
$scope.$apply();
}
google.script.run.withSuccessHandler(gotData).withFailureHandler($scope.gotError).getData();
答案 3 :(得分:2)
我的解决方案是一起摆脱$ q,promise方案。我使用$ rootScope。$ broadcast来更新服务器的范围变量。