我有一个定义背景 $interval 的服务。它监视本地存储以查看是否由于连接问题而没有进行某些服务器更新。当它找到一些更新时,它会定期尝试与服务器联系以获取更新,并在成功时将其从本地存储中删除。
成功后,回调还会更新角度视图/模型的一些属性。这些更改应该会导致 UI 更新,以及它们所做的各种控制器的代码中的其他地方。
但是在该后台服务的 $interval 回调中,更改不会导致 UI 更新。我认为 $apply 可能是某种失败,所以我添加了一个 $rootScope.$apply() 调用。但这会导致错误,因为 $digest 已经在进行中。
这告诉我在回调执行后 $digest 正在运行——这是我所期望的——但它不会导致 UI 更新。
然后我在服务中做了一个 $rootScope.$emit() ,在更新视图/模型之后,并在 UI 应该更新的控制器中监听事件。在侦听器中,我可以看到控制器所基于的视图/模型已由服务成功更新。
这是服务:
app.factory('bkgndUpdates', function($interval, $q, $rootScope, dataContext, localStorage) {
var _interval = null;
var _service = {
get isRunning() { return _interval != null },
};
_service.start = function() {
if( _interval != null ) return;
_interval = $interval(function() {
// check to ensure local storage is actually available
// and has visits to process
var visits = localStorage.visits;
if( !visits || (visits.length == 0) ) return;
var recorded = [];
var promises = [];
var offline = false;
for( var idx = 0; idx < visits.length; idx++ )
{
var visit = visits[idx];
promises.push(dataContext.doVisitAction("/Walk/RecordVisit", visit)
.then(
function(resp) {
offline &= false;
var home = dataContext.findHomeByID(visit.addressID);
if( home != null ) {
// these values should cause a map icon to switch from yellow to blue
// elsewhere in the app that's what happens...but not here.
home.visitInfo.isDirty = false;
home.visitInfo.inDatabase = true;
home.visitInfo.canDelete = true;
home.visitInfo.followUpID = resp.FollowUpID;
}
recorded.push(visit.addressID);
},
function(resp) {
// something went wrong; do nothing, as the item is already
// in local storage
offline |= true;
})
);
}
$q.all(promises).then(
function(resp) {
for( var idx = 0; idx < recorded.length; idx++ )
{
localStorage.removeVisitByID(recorded[idx]);
}
if( !localStorage.hasVisits ) {
$interval.cancel(_interval);
_interval = null;
}
$rootScope.$emit("visitUpdate");
},
function(resp) {
alert("some promise failed");
});
}, 30000);
}
_service.stop = function() {
$interval.cancel(_interval);
_interval = null;
}
return _service;
});
这是地图的控制器:
app.controller("mapCtrl", function ($scope, $rootScope, $location, dataContext) {
$scope.dataContext = dataContext;
$scope.mapInfo = {
center:dataContext.center,
zoom: dataContext.zoom,
pins: dataContext.pins,
};
$scope.$on('mapInitialized', function(evt, map){
$scope.dragend = function() {
$scope.dataContext.center = $scope.map.getCenter();
$scope.dataContext.getMapData($scope.map.getBounds());
}
$scope.zoomchanged = function() {
$scope.dataContext.zoom = $scope.map.getZoom();
$scope.dataContext.getMapData($scope.map.getBounds());
}
$scope.dataContext.getMapData($scope.map.getBounds())
.then(
function() {
$scope.mapInfo.pins = $scope.dataContext.pins;
},
function() {});
});
$scope.click = function() {
dataContext.pinIndex = this.pinindex;
if( dataContext.activePin.homes.length == 1)
{
dataContext.homeIndex = 0;
$location.path("/home");
}
else $location.path("/unit");
};
$rootScope.$on("visitUpdate", function(event) {
// I added this next line to force an update...even though the
// data on both sides of the assignment is the same (i.e., it was
// already changed
$scope.mapInfo.pins = $scope.dataContext.pins;
event.stopPropagation();
});
});
这是(部分)模板(依赖于 ngMap):
<div id="mapframe" class="google-maps">
<map name="theMap" center="{{mapInfo.center.toUrlValue()}}" zoom="{{mapInfo.zoom}}" on-dragend="dragend()" on-zoom_changed="zoomchanged()">
<marker ng-repeat="pin in mapInfo.pins" position="{{pin.latitude}}, {{pin.longitude}}" title="{{pin.streetAddress}}" pinindex="{{$index}}" on-click="click()"
icon="{{pin.icon}}"></marker>
</map>
</div>
那么为什么UI没有更新呢?