LINUX.ORG.RU

Директива в angular

 , ,


0

1

Всем привет. Тут возникла небольшая проблемка, доделываю задачу где есть категории и подкатегории . Решил написать директиву для всего этого, мол при определенном событии если выбран элемент с первого select-а то сразу же обращаюсь к методу API который мне возвращает сразу все подкатегории связанные с выбраной категорией. Повесил это дело пока на простой click , но

link: function(scope, elem, attr, ctrl){
          var divElem = elem[0];

          var ngElem = angular.element(divElem);

          elem.bind('click', function () {
              scope.$apply(function(){
                  if(scope.category.selected !== undefined){
                      $http.get('api_method').then(function (result) {
                          scope.items = result.data;
                          console.log(scope.items);
                      });
                  }else{
                      console.log('Something wrong');
                  }
              });
          });

      }
Для дебага посадил туда console.log() и этот scope.items выводит запрашиваемые элементы, но в select-е они не появляются. А если просто при инициализации контроллера делаю
$http.get('api_method').then(function (result) {
        $scope.items = result.data;
        console.log($scope.items);
    });
То все работает , вернее в select элементы попадают. В чем проблема - не пойму, вроде все правильно делаю.


Ответ на: комментарий от Hater

ДА я тут часто) Просто пытаюсь хорошо разобраться в angular плюс проект на нем, и когда пишу, бывает возникают такие мелкие казусы.

Berdin
() автор топика
Ответ на: комментарий от Berdin

Как-то вот так. Только $http должна быть определена.

link: function(scope, elem, attr, ctrl) {
          var divElem = elem[0];

          var ngElem = angular.element(divElem);

          elem.bind('click', function() {
              if (scope.category.selected !== undefined) {
                  $http.get('api_method').then(function(result) {
                      scope.items = result.data;
                      console.log(scope.items);
                      scope.$apply();
                  });
              } else {
                  console.log('Something wrong');
              }
          });
      }

scope.items ведь обновляется в коллбеке http.get, асинхронно, к тому времени scope.$apply, в который ты передавал свою функцию уже завершился (тот scope.$apply, который я убрал). А его надо вызывать по завершению изменения данных или передавать в коллбек что-то синхронное.

Можно, и, пожалуй, лучше, сделать вот так:

link: function(scope, elem, attr, ctrl) {
          var divElem = elem[0];

          var ngElem = angular.element(divElem);

          elem.bind('click', function() {
              if (scope.category.selected !== undefined) {
                  $http.get('api_method').then(function(result) {
                      scope.$apply(function() {
                          scope.items = result.data;
                      });
                  });
              } else {
                  console.log('Something wrong');
              }
          });
      }
Y ★★
()
Последнее исправление: Y (всего исправлений: 3)
Ответ на: комментарий от Berdin

И кстати делаю как ты показал, но пока ничего не выходит, пофиксил ошибку $digest already in progress добавив

if(!scope.$$phases){

}
Но все ровно пока ничего не падает в select, может я в глобальном понимании не так что либо делаю.

Berdin
() автор топика
Ответ на: комментарий от Hater

зачем изобретать что-то ещё?

Полностью поддерживаю, просто указал на ошибку в конкретном решении.

Y ★★
()
Ответ на: комментарий от Berdin

Странно.

if(!scope.$$phases){

скорее всего (ты ведь не показал, куда вставил) не пофиксило apply, а отменило его

Y ★★
()
Последнее исправление: Y (всего исправлений: 1)
Ответ на: комментарий от Hater

На watch я вешал такой вот код:

$scope.$watch('items', function(newVal, oldVal){
        if(newVal && newVal !== oldVal){
            $scope.items = newVal;
        }
    });
В дериктиве все так же закидываю в scope.items = result.data И все ровно не работает , может причина более глобальна? Angular версии 1.2.23. но не думаю что это причина.

Berdin
() автор топика
Ответ на: комментарий от Hater

Скидываю куски того что есть: В директиве:

link: function(scope, elem, attr, ctrl){

            elem.bind('click', function(){
                if(scope.cat.selected !== undefined){
                    $http.get('api_method').success(function(data, status){
                        scope.items = data;
                        if(!scope.$$phase){
                            scope.$apply();
                        }
                    }).error(function (data, status) {
                        console.log(status);
                    });
                }
            });



        }

А в контроллере такой кусок кода:

$scope.$watch('items', function(newVal, oldVal){
        if(newVal && newVal !== oldVal){
            $scope.items = newVal;
        }
    });

Не знаю даже в чем проблема если чесно.

Berdin
() автор топика
Ответ на: комментарий от Berdin

наврал

Директиву закоменть. Закоменть этот обработчик в директиве.

В контроллере, как минимум, нужен вызов $apply.

Убери проверку «newVal !== oldVal». Проверку надо убрать потому, что:

The listener is called only when the value from the current watchExpression and the previous call to watchExpression are not equal

т.е., проверка избыточна.

Не переживай, watch для объектов делает глубокое сравнение, так что, если listener вызвался, можешь смело items обновлять.

Кстати, проверка if (newVal) наверное, также, в твоём случае будет лишней, потому что никто ведь в твоём коде не собирается удалять items? Но код она не ломает.

Работает?

Y ★★
()
Последнее исправление: Y (всего исправлений: 3)
Ответ на: наврал от Y

Как же директиву закоменить если в ней для items с базы вытягиваю данные, тобишь если я закоменчу то ничего не измениться

Berdin
() автор топика
Ответ на: комментарий от Y

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

Berdin
() автор топика
Ответ на: комментарий от Berdin

Не знаю но может дело в этих select-ах?

<ui-select   ng-model="modelt.selected" theme="bootstrap" search-enabled="searchEnabled"  required>
                                <ui-select-match placeholder="Select something">{{$select.selected.name}}</ui-select-match>
                                <ui-select-choices repeat="item in items | filter: $select.search ">
                                    <div ng-bind-html="item.name | highlight: $select.search"></div>
                                </ui-select-choices>
                            </ui-select>

Они на проекте из-за того что обычные нужны не кастомные select-ы а те что использовались с другой библиотеки там был конфликт с jquery, нашел на git hub вот такую либу select-ов.

Berdin
() автор топика
Ответ на: комментарий от Berdin

Тьфу. Прости, немного непоследователен был.

Попробуй сделать либо так:

link: function(scope, elem, attr, ctrl){
            elem.bind('click', function(){
                if(scope.cat.selected !== undefined){
                    $http.get('api_method').success(function(data, status){
                        scope.items = data;
                    }).error(function (data, status) {
                        console.error(status);
                    });
                }
            });
        }
$scope.$watch('items', function() {
  $scope.$apply();
});

Где $scope во втором случае это тот же самый scope, что и scope в первом.

Y ★★
()
Последнее исправление: Y (всего исправлений: 2)
Ответ на: комментарий от Berdin

Да не нужна тебе директива, в самом вотчере инициируй запрос данных. Т.е. в упрощённом виде:

$scope.$watch('selectModel', function(selectModel){
        if(selectModel){
            $http.get('url').success(function(data){ $scope.data = data /*или что ты хочешь*/});
        }
    });
Hater ★★
()
Ответ на: комментарий от Y

Разве? Никогда в таких случаях не дёргал апплай. Проверил в доке, там пишут

$apply() is used to execute an expression in angular from outside of the angular framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).

Hater ★★
()
Ответ на: комментарий от Hater

Спасибо всем за ответы) Решение Hater помогло) Это я в случае с директивой поехал за хлебушком на танке, усложнил логику малость)))

Berdin
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.