Javascript AngularJS:$scope.$watch未更新自定义指令上从$resource获取的值
我在自定义指令方面遇到了一个让我发疯的问题。 我正在尝试创建以下自定义(属性)指令:Javascript AngularJS:$scope.$watch未更新自定义指令上从$resource获取的值,javascript,json,watch,angularjs,Javascript,Json,Watch,Angularjs,我在自定义指令方面遇到了一个让我发疯的问题。 我正在尝试创建以下自定义(属性)指令: angular.module('componentes', []) .directive("seatMap", function (){ return { restrict: 'A', link: function(scope, element, attrs, controller){ function u
angular.module('componentes', [])
.directive("seatMap", function (){
return {
restrict: 'A',
link: function(scope, element, attrs, controller){
function updateSeatInfo(scope, element){
var txt = "";
for (var i in scope.seats)
txt = txt + scope.seats[i].id + " ";
$(element).text("seat ids: "+txt);
}
/*
// This is working, but it's kind of dirty...
$timeout(function(){updateSeatInfo(scope,element);}, 1000);
*/
scope.$watch('seats', function(newval, oldval){
console.log(newval, oldval);
updateSeatInfo(scope,element);
});
}
}
});
这个“属性类型”指令(称为seatMap)试图将我将通过$resource服务(参见下面的代码)从服务器获取的座位ID列表(例如剧院)显示到div(元素)中
我将其用于以下简单的部分html:
<div>
<!-- This is actually working -->
<ul>
<li ng-repeat="seat in seats">{{seat.id}}</li>
</ul>
<!-- This is not... -->
<div style="border: 1px dotted black" seat-map></div>
</div>
其中“Seats”是一个使用$resources从服务器获取JSON的简单服务
angular.module('myApp.services', ['ngResource'])
.factory('Seats', function($resource){
return $resource('json/seats-:sessionId-:zoneId.json', {}, {});
})
;
app.js(asientos_libres.html是我一直使用的部分):
问题是,即使我在指令的link函数中设置了一个“scope.watch”,以便该作用域可以检查“seats”属性是否已更改以更新ID列表,但它在控制器中更改$scope.seats时(当我们调用“query”时)不起作用
正如您在代码中看到的,我尝试使用$timeout延迟“UpdateSatinfo”的启动,但恐怕这不是目前为止最聪明的解决方案
我还尝试不发出JSON请求,而是在$scope.seats中使用硬编码字典,而且它可以工作,所以这似乎是一个同步问题
注意:UpdateStatInfo只是一个测试函数,我将使用的实际函数要复杂一些
你知道如何应对吗
事先非常感谢
编辑1:添加了app.js,感谢Supr的建议,我正在使用路由器呼叫SeatsCtrl。然而,我仍然有同样的问题
编辑2:已解决!(?)
好啊看来我找到了一个解决方案,这可能不是最好的,但它工作正常!:)
就我在这里所看到的,我们可以使用$timeout(setTimeout上的包装)而没有延迟!这很好,因为我们没有在$timeout内人为地延迟代码的执行,而是让指令在异步请求完成之前不运行它
希望它也适用于长时间等待请求
如果有人知道更好的修复方法,请告诉我 我看不到您在任何地方使用
SeatsCtrl
-控制器?它是如何使用的?您是否验证了它已被激活,并且实际执行了查询
检查SeatsCtrl是否正在使用的最快方法是简单地添加一个console.log('SeatsCtrl actived!')代码>在它里面。如果不是,则将ng controller=“SeatsCtrl”
添加到div
您也可以将手表直接放在控制器内部的座椅上,以确保它不存在范围问题。我也有这个问题。我认为这是一个角度上的问题。GitHub上有一个可能解决这个问题的票证,因为您真正需要的是访问您拥有的资源的promise对象
或者,观察者可以等到承诺兑现后再开火
同时,修复此问题的一种稍微优雅的方法(不需要超时)是重新分配从$resource上的成功回调监视的scope属性。这将导致观察者在适当的时间再次开火
没有延迟的超时只是将延迟函数的计算放在当前堆栈的末尾——在您的情况下,您的资源恰好在那时得到了解决,但是如果服务器遇到了星期一的情况,这可能是一个问题
例如:
$scope.myAttr = MyResource.fetch(
function (resource) { $scope.myAttr = new MyResource(angular.copy(resource)); }
);
问题是watch在默认情况下比较引用而不是对象。将其添加到末尾,使其与值进行比较
scope.$watch('seats', function(newval, oldval){
console.log(newval, oldval);
updateSeatInfo(scope,element);
}, true);
我也有这个问题。这是因为我的变量最初没有在范围中定义为“未定义”。手表似乎对未定义的变量不起作用。毕竟看起来很明显
我第一次尝试使用watch来触发控制器有效设置变量的时间。例如:
myApp.controller('Tree', function($scope, Tree) {
Tree.get({},
function(data) { // SUCCESS
console.log("call api Tree.get succeed");
$scope.treeData = data;
},
function(data) { // FAILURE
console.log("call api Tree.get failed");
$scope.treeData = {};
});
});
我通过在调用服务之前使用空对象初始化变量来解决此问题:
myApp.controller('Tree', function($scope, Tree) {
$scope.treeData = {}; // HERE
Tree.get({},
function(data) { // SUCCESS
console.log("call api Tree.get succeed");
$scope.treeData = data;
},
function(data) { // FAILURE
console.log("call api Tree.get failed");
$scope.treeData = {};
});
});
在这种情况下,watch能够检测到变量的变化。实际上,我通过app.js中的路由器使用了SeatsCtrl,很抱歉之前没有告诉您。我编辑了这篇文章,让它更清楚。我明白了。尽管如此,您是否验证了控制器是否运行,以及查询是否按预期返回座位?正如我所说,在SeatsCtrl中添加一个watch至少会显示查询是否按其应该的方式运行,在这种情况下,可能是scoping.Checked的问题。查询正在运行,但只有在使用超时时才运行。这与指令中发生的问题是一样的。似乎通过Ajax(通过$response)获取数据完全是一个同步问题。。。顺便说一句,范围还可以。警告一句:像这样的深度比较会带来性能成本。当深入观察一组对象而不是单个对象时,这主要是一个问题,但值得记住。
myApp.controller('Tree', function($scope, Tree) {
Tree.get({},
function(data) { // SUCCESS
console.log("call api Tree.get succeed");
$scope.treeData = data;
},
function(data) { // FAILURE
console.log("call api Tree.get failed");
$scope.treeData = {};
});
});
myApp.controller('Tree', function($scope, Tree) {
$scope.treeData = {}; // HERE
Tree.get({},
function(data) { // SUCCESS
console.log("call api Tree.get succeed");
$scope.treeData = data;
},
function(data) { // FAILURE
console.log("call api Tree.get failed");
$scope.treeData = {};
});
});