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

我正在使用AngularJS(我是新手)开发一个小解决方案,我正在尝试使用< dl>创建手风琴效果. &LT峰; dt> &LT峰; dd>标签.我已经定义了一个ng-repeat来从.json文件中创建dl中的dt和dd,它运行良好.

当我想通过指令添加一些功能时,我的问题出现了,所以我可以显示/隐藏< 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元素时什么都不会发生

最佳答案 问题是(如笔中所示)您正在异步加载数据而不是等待解析的承诺.这就是我的意思:

$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告诉指令一切准备就绪.

但是,这可能不是最好的解决方案,因为事件可以在组件之间创建非常微妙的依赖关系.相反,我明确地要求在accordion指令中使用promise,以便父控制器可以指示我们何时准备滚动.所以我补充一下

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指令时使用它

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

Here’s a working solution.
(注意,我必须用其他东西替换$http方法进行测试,你应该用$http就好了)

更新:您还需要使用element.find(selector)替换所有element.children().find(selector)调用以查找元素.我已经更新了笔来覆盖它.

点赞