2016-04-26 103 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