4

Я разрабатываю небольшое решение, используя AngularJS (я новичок в нем), и я пытаюсь создать эффект аккордеона , используя теги <dl> <dt> <dd>. Я определил ng-repeat, чтобы создать как dt, так и dd внутри dl из файла .json, и он работает хорошо.Угловые JS-директивы с ng-repeat, не прошедшие петлю через дочерние элементы

Моя проблема возникает, когда я хочу добавить некоторые функции с помощью директивы, поэтому я могу показать/скрыть элемент <dd>, нажав на элемент <dt>. Код моей директивы, похоже, не работает, так как он действительно не делает то, что я ожидаю, - он ничего не делает. Может быть Директива пытается добавить функциональность до того, как ng-repeat завершил процесс? но для этого я добавил переменную $ timeout.

весь раствор: http://codepen.io/valecarlos/pen/PNdpeZ

код Директива:

app.directive('accordion', function($timeout){ 
return{ 
    restrict: 'E', 
    transclude: true, 
    replace: true, 
    scope: {}, 
    template: '<dl ng-transclude></dl>', 
    link: function(scope,element){ 
     $timeout(function() { 
      console.log(element) 
      console.log(element.children().length);//this gives me 0 

      console.log("im here" + element) 
      element.children().find('dd').css('display','none'); 
      element.find('dt').on('click', function(event){ 
       element.children().find("dd").css('display', 'none') 
       var ddToOpen = angular.element(event.target).next(); 
       ddToOpen.css('display','block'); 
      }); 
     }); 
    } 
}; 
}); 

HTML:

<accordion> 
      <dt ng-repeat-start="article in articles"> 
       //my content 
      </dt> 
      <dd ng-repeat-end=""> 
       //my content 
      </dd> 
<accordion> 

примечание: я пытался реализовать эту гармошку, используя как JQuery и AngularJS, но ничего произойдет, когда я нажму dt

ответ

2

Проблема заключается в том, что вы загружаете данные асинхронно и не дожидаетесь решения обещания. Это то, что я имею в виду:

$http.get('http://www.carlosvalencia.co/news_mock.json').success(function(data) { 
    //$timeout and the DOM stuff will be long gone when we get here :(
    $scope.articles = data; 
}); 

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

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

Это, вероятно, не лучшее решение, поскольку события могут создавать довольно тонкие зависимости между компонентами. Скорее, я прямо просил обещание в директиве аккордеона, так что родительский контроллер может диктовать, когда мы готовы бросить. Поэтому я бы добавил

scope: { 
    promise: '&?' //Ask for an optional promise getter from the parent template 
} 
template: '<dl ng-transclude></dl>', 
link: function(scope,element){ 

    //We'll either wait for the given promise or default to a resolved promise 
    var promise = scope.promise ? scope.promise() : $q.resolve(); 

    //Wait for both that promise AND the additional $timeout before doing DOM stuff 
    promise.then($timeout).then(function() { 
     console.log(element) 
     console.log(element.children().length);//shouldn't be 0 anymore 
     //... the DOM stuff 
    }); 
} 

И теперь нам просто нужно передать обещание $ http от родительского контроллера.

$scope.promise = $http.get('http://www.carlosvalencia.co/news_mock.json').success(function(data) { 
    $scope.articles = data; 
}); 

и использовать, что при использовании директивы аккордеона

<accordion promise="promise" > 
     <dt ng-repeat-start="article in articles"> 
     ... 

Here's a working solution. (Обратите внимание, что я должен был заменить $http метод с чем-то еще для тестирования, вы должны быть очень хорошо с $ HTTP)


Update: Кроме того, необходимо заменить все element.children().find(selector) звонки с element.find(selector) найти элементы. Я обновил перо, чтобы покрыть это.

+0

Спасибо noppa! Теперь я понимаю, где я терпеть неудачу, я пытался реализовать то, что вы предложили, но я не смог заставить его работать и проверять ваш код, скрывает ли он 'dd', когда он загружается? это не работает для меня. ура! – randomguy04

+0

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