带有 ng-repeat 的 Angular JS 指令无法遍历子元素

Angular JS directives with ng-repeat failing to loop through child elements

本文关键字:遍历 元素 指令 ng-repeat Angular JS 带有      更新时间:2023-09-26

我正在使用AngularJS开发一个小解决方案(我是新手),我正在尝试使用<dl> <dt> <dd>标签创建手风琴效果。我已经定义了一个ng-repeat,用于从 .json 文件在 dl 中创建 dt 和 dd,并且效果很好。

当我想通过指令添加一些功能时,我的问题就出现了,所以我可以通过单击 <dt> 元素来显示/隐藏<dd>元素。我的指令的代码似乎不起作用,因为它并没有真正做我期望的事情 - 它什么也没做。也许指令试图在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 元素时没有任何反应

问题是(如笔中所示)您正在异步加载数据,而不是等待承诺解决。这就是我的意思:

$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 会等到 angular 完成模板渲染工作,但它不会等待您的数据加载。当 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">
        ...

这是一个可行的解决方案。(请注意,我不得不用其他方法替换$http方法进行测试,您应该可以使用$http)


更新:您还需要将所有element.children().find(selector)调用替换为element.find(selector)才能找到元素。我已经更新了笔以覆盖它。