我正试图在多个控制器之间分享数据,但却无法找到它应该如何工作(角度方式)。我创建了一个看起来像这样的数据服务:
angular.module('myapp.services')
.service('DataSet', function($rootScope) {
return {
filter: function(filterMethod) {
/// ... do async stuff
$rootScope.$broadcast("Data::filtered");
},
brush: function(brushed) {
/// ... do async stuff
$rootScope.$broadcast("Data::brushed");
},
load: function() {
/// ... do async stuff
$rootScope.$broadcast("Data::loaded");
}
};
});
接下来我想重用和更新此服务中的数据,因此我在控制器中使用它,如下所示:
angular.module('myapp.controllers')
.controller('FilterCtrl', function ($scope, $rootScope, DataSet) {
$scope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if(phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
function updateBrushed() {
$scope.safeApply(function() {
$scope.brushed = DataSet.brushed;
});
};
$scope.brushed = [];
$scope.keepSelected = function() {
DataSet.filter(DataSet.FilterMethod.KEEP);
};
$scope.removeSelected = function() {
DataSet.filter(DataSet.FilterMethod.REMOVE);
};
$scope.$on('Data::brushed', updateBrushed);
$scope.$on('Data::filtered', updateBrushed);
});
我遇到的问题基本上是通过使用saveApply调用来说明的。基本上我从这里得到了这段代码:https://coderwall.com/p/ngisma。但我不明白的是为什么我需要它。据我所知,在更新DataSet服务时,我在'$ angular'内。尽管如此,如果没有调用saveApply,Filter控制器的视图就不会更新($ apply根本不起作用,因为我遇到了申请已经在进行中的问题)。
所以,基本上我的问题归结为:上面的方法是一种分享数据的好方法,如果是这样的话,服务中的变化通知应该如何工作?
更新:根据Julian Hollman的建议,我提出了以下解决方案:http://jsfiddle.net/Ljfadvru/7/。这或多或少地说明了我正在处理的完整工作流程,尽管其中一些工作流程是在小提琴中自动引发的,而不是基于我的实际应用程序中的用户交互。我喜欢这种方法的方法是它只在所有数据更新时发送信号。
根据Ed Hinchliffe的建议,使用参考资料也很不错。但是,我正在开发一个Web可视化框架,我期待成千上万的项目。清除数组和推送新元素(在我看来这个提议的结果)实际上是不可行的(如果我很好地理解这个范例,它也会导致我对每次更改的重新呈现)。如果有进一步改进的建议,我会立即纠正。
答案 0 :(得分:1)
$broadcast
不会触发$apply
而我打赌你的“异步内容”不是来自角度的$ http。
所以在角度和角度之外发生的事情并不知道某些事情发生了变化。
在我看来,在这种情况下最好的事情是为你的异步代码编写一个包装器,并在从后端返回日期之后触发$ apply。不要在控制器中这样做。
答案 1 :(得分:1)
说实话,我不确定您的特定场景中的摘要循环究竟发生了什么,但我不认为您正在以正确的方式接近这一点。
' angular'方式,就是使用承诺。
您的服务应该更像这样:
angular.module('myapp.services')
.service('DataSet', function($rootScope) {
return {
filter: function(filterMethod) {
var returnData = []
$http.get('/some/stuff').then(function(data){
for(i in data){
returnData.push(data[i]);
}
});
return returnData;
}
};
});
这会设置一个空的占位符对象(returnData
),可以立即传递给控制器,但会保留一个引用,以便在数据返回时您可以追溯地填充该对象。由于控制器和服务引用相同的对象,因此只需要工作即可。
这样您就不必担心与$digest
或$apply
或$broadcast
打交道。
您的控制器只需拨打$scope.filtered = DataSet.filter();
修改强>
如果您希望能够从多个控制器访问完全相同的数据:
angular.module('myapp.services')
.factory('DataSet', function($http) {
var cache = {
filtered: []
}
return {
getFiltered: function(){
if(cache.filtered.length) return cache.filtered;
$http.get('/some/url/').then(function(data){
for(i in data){
cache.filtered.push(data[i]);
}
});
}
};
});