2016-04-26 53 views
4

我正在开发一个使用AngularJS的小解决方案(我刚刚接触它),并试图使用<dl> <dt> <dd>标签创建手风琴效果。我已经定义了一个ng-repeat以从.json文件创建dl内的dt和dd,并且它工作正常。ng-repeat的Angular JS指令无法循环通过子元素

当我想通过指令添加一些功能时,出现问题,因此我可以通过单击<dt>元素来显示/隐藏<dd>元素。我的指令代码似乎没有工作,因为它并没有真正做我期望的 - 它没有做任何事情。 也许该指令试图在ng-repeat完成它的过程之前添加功能?但为此我添加了$超时变量。

整体解决方案: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但没有实现这个手风琴当我点击时会发生3210元素

回答

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操作完成后,没有要列出的文章,因此没有要查找的元素。

现在,您需要做的是以某种方式告诉您的指令,以便在数据准备就绪之前延迟执行它的操作。我没有一个明确的适合所有目的的解决方案来做到这一点。 Angular为组件之间的通信提供了几种方法,它们在某些情况下都可以很好地工作,但可能对其他组织没有好处。例如,在这里最简单的事情可能就是使用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罚款)


更新:您还需要与element.find(selector)全部更换element.children().find(selector)电话找要素。我已经更新了这支笔。

+0

谢谢noppa!我现在明白我失败的地方,我一直在努力实现你的建议,但我一直无法得到它的工作,并检查你的codepen,它加载时是否隐藏'dd'?它似乎不适合我。干杯! – randomguy04

+0

你是对的,与选择器有一个单独的问题。我更新了答案和笔,现在它应该可以工作。 – noppa