pofigizm
@pofigizm

Как задержать построение документа или обработку директивы до получения данных с сервера?

js файл:
'use strict';
angular.module('myApp')
  .factory('Order', ['$resource',
    function ($resource) {
      return $resource('/api/orders/:id', { id: 'all' } );
    }
  ])
  .controller('orderCtrl', ['$scope', '$routeParams', 'Order',
    function ($scope, $routeParams, Order) {
// Если здесь не заполнить скоп то в обработке директивы будет ошибка
      $scope.orders = [{
        name: 'name'
      }];
      console.log('controller');
      Order.query({id: 'all'}, function(orders) {
        $scope.orders = orders;
        console.log('get data from server');
      });
    }
  ])
  .directive('orderDrct', ['$compile',
    function ($compile) {
      return {
        restrict: 'A',
        link: function (scope, element) {
          var html = '';
          angular.forEach(scope.orders, function (ord) {
            html += '<h4>' + ord.name + '</h4>';
          });
          element.append($compile(html)(scope));
          console.log('end of directive');
        }
      };
    }
  ]);


в консоли сообщения в таком порядке:
controller
end of directive
get data from server


и часть моего html (у меня все в jade, надеюсь понятно будет):
div.marketing 
  h3 It made with ng-repeat
  div.order(ng-repeat='order in orders')
    h4 {{order.name}}

div.marketing 
  h3 It made with derective
  div(order-drct)


1-й блок построен с использованием ng-repeat и он перестраивается после прихода данных
2-й собственно то что мне нужно, но я хочу чтоб он построился когда с сервера придут данные.

UPDATE 29.05.14! (вытащил сюда из комментария)

Я не хочу повторить ng-repeat, у меня совсем другая задача.
В моей форме, набор полей строится по данным пришедшим с сервера (максимально упростил, чтоб понять задачу):
jsbin.com/tafuw/3/watch

Собственно у меня все работает, проблем нету, но мнения о правильности или не правильности такого решения мне интересны.

UPDATE 31.05.14!

Вообще то, что мне нужно, можно реализовать вообще без своей директивы, используя ng-switch.
Конечно это уже не совсем по теме вопроса, но все же оставлю здесь, может кому понадобится.
jsbin.com/repidexo/2/watch
  • Вопрос задан
  • 2653 просмотра
Решения вопроса 1
Я использовал $broadcast для такой задачи. В вашем случае - добавить в контроллер отправку сообщения 'dataloaded':
Order.query({id: 'all'}, function(orders) {
        $scope.orders = orders;
        console.log('get data from server');
        $scope.$broadcast('dataloaded');
      });


А в директиве сделать инициализацию при наступлении события dataloaded:
.directive('orderDrct', ['$compile',
    function ($compile) {
      return {
        restrict: 'A',
        link: function (scope, element) {
          scope.$on('dataloaded', function ()
          {
              // Ваш код
              console.log('end of directive');
          });          
        }
      };
    }
  ]);


В этом случае ваш код выполниться после того как придет событие dataloaded.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
pofigizm
@pofigizm Автор вопроса
Есть конечно один вариант с помощью таймера:
// ...
        link: function (scope, element) {
          setTimeout(function () {
            var html = '';
            angular.forEach(scope.orders, function (ord) {
              html += '<h4>' + ord.name + '</h4>';
            });
            element.append($compile(html)(scope));
            console.log('end of directive');
          }, 1000);
        }
// ...

Также можно внутри таймера проверять если данные пришли то выполнять, если нет то еще подождать.
Может быть есть более изящное решение?

++ еще через 1 час...

Нашел вариант который меня в принципе устраивает:
// ...
  .directive('orderDrct', ['$compile', 'Order',
    function ($compile, Order) {
      return {
        restrict: 'A',
        link: function (scope, element) {
          Order.query({id: 'all'}, function(orders) {
            scope.orders = orders;
            var html = '';
            angular.forEach(scope.orders, function (ord) {
              html += '<h4>' + ord.name + '</h4>';
            });
            element.append($compile(html)(scope));
          });
        }
      };
    }
  ])
// ...


т.е. перенести запрос к серверу в функцию линковки и в его коллбеке уже выполнить код.

Есть еще варианты?
Ответ написан
Комментировать
maxaon
@maxaon
Вам надо больше уделить времени изучению angular и его философии.

В самом простом случае код вашей директивы будет выглядеть так:
jsbin.com/dekic/13/edit
Если вам надо следить за изменениями коллекции, директива будет выглядеть так
jsbin.com/dekic/20/edit
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы