javascript - AngularJS : What is the best way to bind to a global event in a directive -


imagine situation in angularjs want create directive needs respond global event. in case, let's say, window resize event.

what best approach this? way see it, have 2 options: 1. let every directive bind event , it's magic on current element 2. create global event listener dom selector each element on logic should applied.

option 1 has advantage have access element on want operations. but...options 2 has advantage not have bind multiple times (for each directive) on same event can performance benefit.

let's illustrate both options:

option 1:

angular.module('app').directive('mydirective', function(){       function dosomethingfancy(el){          // in here have our operations on element     }      return {         link: function(scope, element){              // bind window resize event each directive instance.              angular.element(window).on('resize', function(){                   dosomethingfancy(element);              });         }     }; }); 

option 2:

angular.module('app').directive('mydirective', function(){      function dosomethingfancy(){          var elements = document.queryselectorall('[my-directive]');          angular.foreach(elements, function(el){              // in here have our operations on element          });     }      return {         link: function(scope, element){              // maybe have in here, maybe not.         }     };      // bind window resize event once.     angular.element(window).on('resize', dosomethingfancy); }); 

both approaches working fine feel option 2 not 'angular-ish'.

any ideas?

i have chosen method, localise global events, window resizing. converts javascript events angular scope events, via directive.

app.directive('resize', function($window) {   return {     link: function(scope) {       function onresize(e) {         // namespacing events name of directive + event avoid collisions         scope.$broadcast('resize::resize');       }        function cleanup() {         angular.element($window).off('resize', onresize);       }        angular.element($window).on('resize', onresize);       scope.$on('$destroy', cleanup);     }   } }); 

which can used, in basic case, on root element of app

<body ng-app="myapp" resize>... 

and listen event in other directives

<div my-directive>.... 

coded as:

app.directive('mydirective', function() {   return {     link: function(scope, element) {       scope.$on('resize::resize', function() {         dosomethingfancy(element);       });     });   } }); 

this has number of benefits on other approaches:

  • not brittle exact form on how directives used. option 2 requires my-directive when angular treats following equivalent: my:directive, data-my-directive, x-my-directive, my_directive can seen in guide directives

  • you have single place affect how javascript event converted angular event, affects listeners. later want debounce javascript resize event, using lodash debounce function. amend resize directive to:

    angular.element($window).on('resize', $window._.debounce(function() {   scope.$broadcast('resize::resize'); },500)); 
  • because doesn't fire events on $rootscope, can restrict events part of app moving put resize directive

    <body ng-app="myapp">   <div>     <!-- no 'resize' events here -->   </div>   <div resize>     <!-- 'resize' events $broadcast here -->   </div> 
  • you can extend directive options, , use differently in different parts of app. want different debounced versions in different parts:

    link: function(scope, element, attrs) {   var wait = 0;   attrs.$observe('resize', function(newwait) {     wait = $window.parseint(newwait || 0);   });   angular.element($window).on('resize', $window._.debounce(function() {     scope.$broadcast('resize::resize');   }, wait)); } 

    used as:

    <div resize>   <!-- undebounced 'resize' angular events here --> </div> <div resize="500">   <!-- 'resize' debounced 500 milliseconds --> </div> 
  • you can later extend directive other events might useful. maybe things resize::heightincrease. resize::heightdecrease, resize::widthincrease, resize::widthdecrease. have 1 place in app deals remembering , processing exact dimensions of window.

  • you can pass data along events. viewport height/width might need deal cross-browser issues (depending on how far need ie support, , whether include library you).

    angular.element($window).on('resize', function() {   // http://stackoverflow.com/a/11744120/1319998   var w = $window,       d = $document[0],       e = d.documentelement,       g = d.getelementsbytagname('body')[0],       x = w.innerwidth || e.clientwidth || g.clientwidth,       y = w.innerheight|| e.clientheight|| g.clientheight;   scope.$broadcast('resize::resize', {     innerwidth: x,     innerheight: y   }); }); 

    which gives single place add data later. e.g. want send difference in dimensions since last debounced event? add bit of code remember old size , send difference.

essentially design provides way convert, in configurable manner, global javascript events local angular events, , local not app, local different parts of app, depending on placement of directive.


Comments

Popular posts from this blog

java - Intellij Synchronizing output directories .. -

git - Initial Commit: "fatal: could not create leading directories of ..." -