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 = {};
});
});