2013-07-17 52 views
2

試圖讓3D黨jQuery庫有兩個非常簡單的自定義指令的工作:AngularJS - 指令,NG-重複,NG-點擊和jQuery

無法獲得納克單擊工作,不知道如何從鏈接函數中的重複元素中獲取數據。

當你點擊一張幻燈片時,它的名字和隱藏的數據應該附加在它下面的列表中。

jsfiddle

angular.module('sm', []) 
.directive('selector', function() { 
return { 
    restrict: "E", 
    template: '<div class="swiper-wrapper">' + 
     '<div class="swiper-slide" ng-repeat="slide in slides">' + 
     '<h1 ng-click="selected(slide)">{{ slide.name }}</h1>' + 
     '</div></div>', 
    replace: true, 
    controller: ['$scope', '$timeout', function ($scope, $timeout) { 

     $scope.slides = [{ 
      name: 'one', 
      hidden: 'kittens' 
     }, { 
      name: 'two', 
      hidden: 'puppies' 
     }, { 
      name: 'three', 
      hidden: 'bacon' 
     }]; 
     $timeout(function() { // important! 
      $.swiper.init(); 
     }); 

     // ng-click never fired due to the jQuery slider plugin 
     $scope.selected = function (data) { 
      console.log('ng-click called $scope.selected'); 
      $scope.$broadcast('slideSelected', data); 
     }; 
    }], 
    link: function linkFn(scope, lElement, attrs) { 

     lElement.on('click', function (el) { 
      console.log('lElement on click called'); 
      // how do I get access to the clicked element's data? 
      scope.$broadcast('slideSelected', el); 
      $ 
     }) 
    } 
} 
}) 
     .directive('selected', function() { 
     return { 
      restrict: "E", 
      template: '<ul>' + 
       '<li ng-repeat="selection in selected">{{ selection }}</li>' + 
       '</ul>', 
      replace: true, 
      controller: ['$scope', function ($scope) { 
       var selected = ['Add to me', 'please']; 
       $scope.selected = selected; 
       $scope.$on('slideSelected', function (data) { 
        $scope.$apply(function() { 
         selected.push(selected); 
        }) 
       }); 
      }], 
     } 
    }) 
     .controller('MyCtrl', function ($scope) {}); 

    $.swiper = { 
     init: function() { 
      var mySwiper = $('.swiper-container').swiper({ 
       mode: 'horizontal', 
       loop: true 
      }); 
     } 
    }; 
+0

當您單擊應該在哪裏發生,那該多好? –

+0

更新了你的問題 –

回答

4

注意到這裏的幾件事情只是使用鏈接功能而不是控制器。可以將$timeout依賴關係移至指令工廠功能。

2.您的指令共享範圍;由於指令並未被告知創建新的或隔離的範圍,因此它們各自的屬性(函數中的一個函數和另一箇中的值)相互覆蓋。

隔離範圍解決了這個問題,但是因爲範圍不再連接,所以您不能執行scope.$broadcast。您的選擇是

  1. 廣播父範圍的事件:scope.$parent.$broadcast
  2. 廣播上$rootScope事件(這是所有範圍內的最終母公司)
  3. 使用共享服務,而不是事件廣播(此大概是我會做的)

3。如果你看看the documentation for Scope#$on,你會發現監聽器函數的第一個參數是被觸發的事件; 的參數將您的自定義數據發送到$broadcast函數中。

4.在角1.1.x的版本中,你不能在ng-repeat屬性相同的數據,而無需添加track by子句告訴角哪些數據應該用它來確定數據是否真的重複。這裏我們使用$index

<li ng-repeat="selection in selected track by $index">{{ selection }}</li> 

解決這些問題,使我們向這個代碼:http://jsfiddle.net/BinaryMuse/hCdJA/;問題在於ng-click仍然被jQuery插件所佔用。在Angular中使用第三方jQuery插件時,這類問題並不罕見,答案通常是編寫一個指令來封裝插件的功能。


努力一點後,我有一組指令,使包裝組隊,探索的功能(至少是位我們所關心的;組隊,探索在API方面有相當廣泛的表面積,所以我沒有覆蓋這一切)以一種相當可重用的方式。我很難讓setDatagetData正常工作(我懷疑它是插件中的一個錯誤),所以最終以常規的data()調用和外部對象來存儲回調。

在我們進入的代碼,你可以在這裏看到一個工作演示:http://jsfiddle.net/BinaryMuse/UruNG/

下面是最終HTML:

<div ng-app="sm"> 
    <div ng-controller="MyCtrl"> 
    <swiper> 
     <slide ng-repeat="slide in slides" ng-click="select(slide)"> 
     <h1>{{slide.name}}</h1> 
     </slide> 
    </swiper> 
    <ul> 
     <li ng-repeat="item in items track by $index">{{item | json}}</li> 
    </ul> 
    </div> 
</div> 

我已經分裂出去的swiperslide元素,使它們可重複使用和可組合的; slide指令使用require屬性獲取由父代swiper指令定義的控制器,以訪問其公開的函數。

這裏的JavaScript來使其工作:

angular.module('sm', []) 
.directive('swiper', function($timeout) { 
    return { 
    restrict: 'EA', 
    template: "<div class='swiper-container'>" + 
     "<div class='swiper-wrapper'></div>" + 
     "<div style='display: none' ng-transclude></div>" + 
     "</div>", 
    replace: true, 
    transclude: true, 
    // We use a controller here so the slide directive 
    // can require it and call `addSlide`. 
    controller: function($element) { 
     var newSlides = []; 
     var mySwiper = null; 
     var slideCount = 0; 
     var callbacks = {}; 

     // Attached directly to the controller so other directives 
     // have access to it. 
     this.addSlide = function(html, callback) { 
     if (mySwiper) { 
      var newSlide = mySwiper.createSlide(html.html()); 
      // Hackily save off the callback based on 
      // a unique ID since getData() for 
      // swiper.clickedSlide doesn't appear to work 
      // when using setData() on newSlide. 
      newSlide.data('slideNumber', ++slideCount); 
      mySwiper.appendSlide(newSlide); 
      callbacks[slideCount] = callback; 
      mySwiper.swipeTo(0, 0, false); 
     } else { 
      // mySwiper hasn't been initialized yet; save 
      // the slide off in an array so we can add it later. 
      newSlides.push({html: html, callback: callback}); 
     } 
     }; 

     $timeout(function() { 
     mySwiper = $element.swiper({ 
      mode: 'horizontal', 
      loop: true, 
      onSlideClick: function(swiper) { 
      // Look up the callback we saved off and call it. 
      var clicked = swiper.clickedSlide; 
      var slideNumber = clicked.data('slideNumber'); 
      var callback = callbacks[slideNumber]; 
      if (callback) callback(); 
      } 
     }); 

     // Now that mySwiper has been initialized, iterate 
     // over any calls to `addSlide` that happened 
     // before we were ready and add them to the swiper. 
     for (var i = 0; i < newSlides.length; i++) { 
      var slide = newSlides[i]; 
      this.addSlide(slide.html, slide.callback); 
     } 
     }.bind(this)); 
    } 
    } 
}) 
.directive('slide', function() { 
    return { 
    restrict: 'EA', 
    // Look for a parent `swiper` element and get its controller 
    require: '^swiper', 
    template: "<div class='swiper-slide' ng-transclude></div>", 
    replace: true, 
    transclude: true, 
    link: function(scope, elem, attrs, swiper) { 
     swiper.addSlide(elem, function() { 
     scope.$apply(attrs.ngClick); 
     }); 
    } 
    } 
}) 
.controller('MyCtrl', function ($scope) { 
    $scope.slides = [{ 
    name: 'one', 
    hidden: 'kittens' 
    }, { 
    name: 'two', 
    hidden: 'puppies' 
    }, { 
    name: 'three', 
    hidden: 'bacon' 
    }]; 

    $scope.items = ["Add to me", "please"]; 

    $scope.select = function(slide) { 
    $scope.items.push(slide); 
    }; 
}); 

你可以看到,我們已經成功地讓所有的具體組隊,探索的功能的指令,而數據我們遍歷(slides)並且觸發回調(select)附加到控制器作用域,它們更有意義(因爲它們是應用程序特定的數據)。

此外,工作演示可以在這裏找到:http://jsfiddle.net/BinaryMuse/UruNG/

+0

非常感謝,非常感謝。 –

+0

沒問題;如果您還有其他問題,請隨時[ping me](http://brandontilley.com/contact.html)。 –

1

我注意到兩件事:

1)你不需要邏輯函數都沒有。當你使用模板時,angular會負責編譯模板內的指令。此外,您的鏈接函數綁定到選擇器元素,而不是每個li,因此您無法確定哪個數據對象被點擊。

2)您的指令使用繼承的範圍,但都將不同的事物分配給相同的屬性名稱。在選擇器指令中,您將$scope.selected分配爲一個函數。在選定的指令中,您將$scope.selected指定爲值的數組。這些干擾因爲他們使用相同的範圍。我能夠通過將第一個更改爲$scope.select = function(data)...來修復它。

3)你寫了你的事件處理程序來查找數據作爲第一個參數。該事件是第一個參數,之後的任何參數綁定到廣播事件時傳遞的參數,所以它會更好,如$scope.$on('slideSelected', function(event, data)...

4)您的事件處理程序不需要應用範圍,因爲這將自動發生,而只是更新模型。

更新的小提琴是here

1.如果你不這樣認爲孩子的指令應該能夠require它並訪問其控制器創建指令,你可以考慮: