Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to safely clean up AngularJS event binding in a directive

Tags:

I have an Angular directive that sets an element's height equal to the inner height of the browser window (+/- a given offset). This directive responds to the window's "resize" event and adjusts its height accordingly. When the scope of my directive emits the '$destory' event, I remove the binding to the "resize" event (I think leaving it in place would cause some issues, correct me if I'm wrong).

I don't know how to do this event detachment in a "safe" way. What if I have multiple instances of this directive throughout my app and what if I have other directives that attach to the 'resize' event?

JQuery has the concept of event namespace which seems like a good solution, but Angular's implementation (JQLite) does not support this. I'd rather not use JQuery since I'm already using Angular, so what do I do?

Here's the code for my directive as it is today

window.angular.module('arcFillClient', [])     .directive('arcFillClientY', ['$window',         function ($window) {              function link($scope, el, attrs) {                  var setHeight,                     onResize,                     cleanUp;                  setHeight = function (offSetY) {                     var newHeight;                     offSetY = offSetY || 0;                     newHeight = Math.max($window.innerHeight + parseInt(offSetY, 10)) + 'px';                     el.height(newHeight);                 };                  onResize = function () {                     var offset;                     offset = attrs.arcFillClientY || 0;                     setHeight(offset);                 };                  attrs.$observe('arcFillClientY', setHeight);                 window.angular.element($window).on('resize', onResize);                  cleanUp = function () {                     window.angular.element($window).off('resize');                 };                  $scope.$on('$destroy', cleanUp);             }             return {                 link: link             }; 

UPDATE Looks like a case of RTFM, but just in case anyone else wanders in here, here is some more info. Passing the original function (in my case OnResize) to the .off() works to isolate the scope of the .off() function. From the docs:

A handler can also be removed by specifying the function name in the handler argument. When jQuery {ahem... JQLite} attaches an event handler, it assigns a unique id to the handler function.

Here's the updated cleanUp function from my directive:

cleanUp = function () {     window.angular.element($window).off('resize', onResize); }; 

Thanks tasseKATT, Karolis and Hans for your contributions.

like image 692
Bill Sourour Avatar asked Apr 12 '14 14:04

Bill Sourour


People also ask

Which directive is used for data binding in AngularJS?

A - ng-bind directive binds the AngularJS Application data to HTML tags.

What is $destroy in AngularJS?

$scope.$destroy() This means that calling $scope. $destroy() manually from example within a directive's link function will not remove a handler attached via for example element. on , nor the DOM element itself.

How do you pass an event in directive?

You can pass your function save directly as an @Input to your directive. On click, you can run this function, and again, use an @Output to get the subscription. You can also directly take the reference to your element in the constructor, and on click, call the function of that element.

Which directive do we use to inform AngularJS about the parts controlled by it?

The ngRef attribute tells AngularJS to assign the controller of a component (or a directive) to the given property in the current scope. It is also possible to add the jqlite-wrapped DOM element to the scope. The ngRepeat directive instantiates a template once per item from a collection.


1 Answers

Pass the same function reference to off as you pass to on:

window.angular.element($window).off('resize', onResize); 

Instead of:

window.angular.element($window).off('resize'); 

Demo - Passing function reference to off: http://plnkr.co/edit/1rfVPNXl6TrEcuYvzPAj?p=preview

Demo - Not passing function reference to off: http://plnkr.co/edit/IsLqSLAzNcHqDnhMty7Q?p=preview

The demos contain two directives both listening to the window resize event. Use the vertical separator between the code and the preview to trigger the event.

You will notice that if you destroy one the other will keep working when passing function reference to off. If you don't, both will stop working.

like image 93
tasseKATT Avatar answered Sep 22 '22 11:09

tasseKATT