Подтвердить что ты не робот

AngularJS: $scope. $Watch не обновляет значение, полученное из $resource в пользовательской директиве

У меня проблема с пользовательскими директивами, которые сводят меня с ума. Я пытаюсь создать следующую настраиваемую (атрибутную) директиву:

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 kind of dirty...
                    $timeout(function(){updateSeatInfo(scope,element);}, 1000);
                */

                scope.$watch('seats', function(newval, oldval){
                    console.log(newval, oldval);
                    updateSeatInfo(scope,element);
                });
            }
        }
    });

Эта директива типа "атрибут-тип" (например, sitMap) пытается показать список идентификаторов мест (например, для театра), которые я выберу с сервера через службу ресурсов $(см. код ниже) в 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>

И это контроллер, который загружает область действия:

function SeatsCtrl($scope, Seats) {
    $scope.sessionId = "12345";
    $scope.zoneId = "A";
    $scope.seats = Seats.query({sessionId: $scope.sessionId, zoneId: $scope.zoneId});
    $scope.max_seats = 4;
}

Где "Места" - это простая служба, использующая $resources для извлечения JSON с сервера

angular.module('myApp.services', ['ngResource'])
    .factory('Seats', function($resource){
        return $resource('json/seats-:sessionId-:zoneId.json', {}, {});
    })
;

app.js(asientos_libres.html - это часть, которую я использовал):

angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'componentes']).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/view1', {templateUrl: 'partials/asientos_libres.html', controller: SeatsCtrl});
    $routeProvider.otherwise({redirectTo: '/view1'});
  }]);

Проблема заключается в том, что я установил "scope. $watch" в функции ссылок директивы, чтобы область действия могла проверить, изменился ли атрибут "мест", чтобы обновить список идентификаторов, это не работающий в данный момент $scope.seats меняется в контроллере (когда мы вызываем "запрос" ).

Как вы могли видеть в коде, я попытался использовать $timeout для задержки запуска "updateSeatInfo", но я боюсь, что это не самое умное решение на сегодняшний день...

Я также пытался не делать запрос JSON, но использовать словарь с жестким кодом в $scope.seats, и он работает, поэтому кажется, что это вопрос синхронизации.

Примечание: updateSeatInfo - это просто тестовая функция, фактическая функция, которую я буду использовать, немного сложнее.

Любая идея о том, как справиться с этим?

Большое вам спасибо заранее!

Изменить 1: Добавлен app.js, где я использую маршрутизатор для вызова SeatsCtrl, благодаря Supr для совета. Тем не менее, у меня все еще такая же проблема.

Изменить 2: Решено! (?) ОК! Кажется, я нашел решение, которое может быть не лучшим, но оно работает правильно!:) Насколько я мог видеть здесь http://docs.angularjs.org/api/ng.$timeout, мы можем использовать $timeout (обертка над setTimeout) без задержки! Это здорово, потому что мы не искусственно задерживаем выполнение нашего кода внутри $timeout, но мы делаем директиву не запускать его до завершения асинхронного запроса.

Надеюсь, что он будет работать и для запросов с длинным ожиданием...

Если кто-то знает лучший способ его исправить, скажите!

4b9b3361

Ответ 1

Проблема заключается в том, что часы сравнивают ссылку вместо объекта по умолчанию. Добавьте, истинно до конца, чтобы сравнить это значение.

scope.$watch('seats', function(newval, oldval){
                console.log(newval, oldval);
                updateSeatInfo(scope,element);
            }, true);

Ответ 2

У меня тоже была эта проблема. Это было связано с тем, что моя переменная была сначала не определена "undefined" в области. Кажется, что часы не работают с переменными undefined. Кажется очевидным после всех.

Сначала я пытался использовать часы для запуска, когда моя переменная будет эффективно установлена ​​контроллером. Пример:

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

В этом случае часы смогли обнаружить изменение в переменной.

Ответ 3

Я не вижу, что вы используете SeatsCtrl -controller где угодно? Как он используется? И проверили ли вы, что он активирован и что запрос действительно выполняется?

Самый быстрый способ проверить, используется ли SeatsCtrl, - просто добавить в него console.log('SeatsCtrl actived!');. Если это не так, добавьте ng-controller="SeatsCtrl" в div.

Вы также можете поставить часовую панель на сиденья непосредственно внутри контроллера, чтобы убедиться, что это не проблема с просмотром.

Ответ 4

У меня тоже есть эта проблема. Я думаю, что это проблема в Angular. В GitHub есть билет на "beef up $resource futures" , который, вероятно, затронет эту проблему, поскольку вам действительно нужен доступ к обещанию объект для вашего ресурса.

Или наблюдатели могут подождать, пока не будут решены обещания.

Тем временем, немного более элегантный способ исправить это, который не требует тайм-аута, состоит в том, чтобы переназначить свойство scope, которое просматривается из обратного вызова успеха в ресурсе $. Это заставит наблюдателя снова срабатывать в соответствующее время.

Тайм-аут без задержки просто оценивает отложенную функцию в конце текущего стека - в вашем случае ваш ресурс был разрешен к тому времени, но это может быть проблемой, если сервер имеет случай понедельника.

Пример:

$scope.myAttr = MyResource.fetch(
  function (resource) { $scope.myAttr = new MyResource(angular.copy(resource)); }
);