javascript - AngularJS - Directives, ng-repeat, ng-click and Jquery -


trying 3d party jquery library working 2 pretty simple custom directives:

can't ng-click work , not sure how data repeated element in link function.

when click on slide it's name , hidden data should append on list below it.

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 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 access 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 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             });         }     }; 

a few things of note here:

1. if you're not creating directive in such way child directives should able require , access controller, may consider using link function instead of controller. $timeout dependency can moved directive factory function.

2. directives sharing scope; since directives weren't told create new or isolate scope, respective scope.selected properties (a function in 1 , value in other) overwriting each other.

an isolate scope fixes problem, can't scope.$broadcast scopes no longer connected. choices are

  1. broadcast event on parent scope: scope.$parent.$broadcast
  2. broadcast event on $rootscope (which ultimate parent of scopes)
  3. use shared service instead of event broadcasts (this do)

3. if @ the documentation scope#$on, you'll see first argument listener function event triggered; second argument custom data sent $broadcast function.

4. in 1.1.x versions of angular, can't have identical data in ng-repeat attribute without adding track by clause tell angular data should use determine if data duplicate. here use $index:

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

addressing these issues gets code: http://jsfiddle.net/binarymuse/hcdja/; problem ng-click still being eaten jquery plugin. class of issue isn't uncommon when working third-party jquery plugins in angular, , answer write directive wrap plugin's functionality.


after bit of effort, have set of directives wrap swiper's functionality (at least bit care about; swiper has pretty wide surface area in terms of api, didn't cover all) in reusable way. had hard time getting setdata , getdata work correctly (i suspect it's bug in plugin) ended hacking way around regular data() calls , external object store callbacks.

before code, can see working demo here: http://jsfiddle.net/binarymuse/urung/

here's final 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 $index">{{item | json}}</li>     </ul>   </div> </div> 

i've split off swiper , slide elements make them reusable , composable; slide directive uses require attribute @ controller defined parent swiper directive access function exposes.

here's javascript make work:

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,     // use controller here slide directive     // can require , call `addslide`.     controller: function($element) {       var newslides = [];       var myswiper = null;       var slidecount = 0;       var callbacks = {};        // attached directly controller other directives       // have access it.       this.addslide = function(html, callback) {         if (myswiper) {           var newslide = myswiper.createslide(html.html());           // hackily save off callback based on           // unique id since getdata()           // swiper.clickedslide doesn't appear 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           // slide off in array can add later.           newslides.push({html: html, callback: callback});         }       };        $timeout(function() {         myswiper = $element.swiper({           mode: 'horizontal',           loop: true,           onslideclick: function(swiper) {             // callback saved off , call it.             var clicked = swiper.clickedslide;             var slidenumber = clicked.data('slidenumber');             var callback = callbacks[slidenumber];             if (callback) callback();           }         });          // myswiper has been initialized, iterate         // on calls `addslide` happened         // before ready , add them swiper.         (var = 0; < newslides.length; i++) {           var slide = newslides[i];           this.addslide(slide.html, slide.callback);         }       }.bind(this));     }   } }) .directive('slide', function() {   return {     restrict: 'ea',     // parent `swiper` element , 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 me", "please"];    $scope.select = function(slide) {     $scope.items.push(slide);   }; }); 

you can see we've managed keep swiper-specific functionality directives, while data we're looping on (slides) , callback fire (select) attached controller scope, make more sense (as application-specific data).

again, working demonstration can found here: http://jsfiddle.net/binarymuse/urung/


Comments

Popular posts from this blog

php - Calling a template part from a post -

Firefox SVG shape not printing when it has stroke -

How to mention the localhost in android -