Click everywhere but event here

I wonder how I would implement the Click event everywhere, but in this element.

I have something that you can compare with the list of files in the file explorer. You can select certain elements, but if you go beyond the control of an element, it needs to undo everything.

enter image description here

Added screenshot to make it more understandable. So I want that if I click somewhere, but on language elements, it should fire an event.

Update

To clarify, I am not asking how to do this using jQuery.

+34
javascript angularjs
Oct 17
source share
8 answers

EDIT: There were a few problems in this old, old answer.

* Also: Wiki community tagging (no dots for me) because errors

  • N calls N using the directive. This is probably undesirable for use within the same field with the corresponding expressions.

  • NOTHING TO LEARN BY MEANS OF EVENTS !!!! BADLY! BADLY! BADLY!

So, I am updating this answer. I hope this didn’t cause anyone too much trouble.

Updated Answer

Here a new plunker appeared with these problems ... There are probably other things that individual application developers face. This is just an example of how to deal with this problem.

app.factory('clickAnywhereButHereService', function($document){ var tracker = []; return function($scope, expr) { var i, t, len; for(i = 0, len = tracker.length; i < len; i++) { t = tracker[i]; if(t.expr === expr && t.scope === $scope) { return t; } } var handler = function() { $scope.$apply(expr); }; $document.on('click', handler); // IMPORTANT! Tear down this event handler when the scope is destroyed. $scope.$on('$destroy', function(){ $document.off('click', handler); }); t = { scope: $scope, expr: expr }; tracker.push(t); return t; }; }); app.directive('clickAnywhereButHere', function($document, clickAnywhereButHereService){ return { restrict: 'A', link: function(scope, elem, attr, ctrl) { var handler = function(e) { e.stopPropagation(); }; elem.on('click', handler); scope.$on('$destroy', function(){ elem.off('click', handler); }); clickAnywhereButHereService(scope, attr.clickAnywhereButHere); } }; }); 

Original answer (with corrections to remove event handlers)

You were close to the one answer you found, but I put together a bar to show you that it was missing.

 app.directive('clickAnywhereButHere', function($document){ return { restrict: 'A', link: function(scope, elem, attr, ctrl) { var elemClickHandler = function(e) { e.stopPropagation(); }; var docClickHandler = function() { scope.$apply(attr.clickAnywhereButHere); }; elem.on('click', elemClickHandler); $document.on('click', docClickHandler); // teardown the event handlers when the scope is destroyed. scope.$on('$destroy', function() { elem.off('click', elemClickHandler); $document.off('click', docClickHandler); }); } } }) 

HTML

 <a click-anywhere-but-here="clickedSomewhereElse()" ng-click="clickedHere()">Don't Click Me!</a> 
+66
Oct 17
source share

The problem with the currently accepted answer is that if you use the directive several times, each DOM element that has an attached directive will prevent “bubbling” (so if you have two elements and you click on them), the reverse calls will both be blocked).

EDIT - avoid jQuery, clear . Define a function in your area and pass it directly to this directive (without parentheses), and the event will be passed to it when called.

 app.directive('clickAnywhereButHere', function($document, $parse) { return { restrict: 'A', scope: { callback : '=clickAnywhereButHere' }, link: function(scope, element, attr, ctrl) { var handler = function(event) { if (!element[0].contains(event.target)) { scope.callback(event); } }; $document.on('click', handler); scope.$on('$destroy', function() { $document.off('click', handler); }); } } }); 

HTML usage

 <a click-anywhere-but-here="myFunction"></a> 

Use in the controller

  $scope.myFunction = function (event) { ... } 

-

Note that you may need to wrap scope.callback(event) with scope.$apply()

+28
May 24 '13 at 19:14
source share

If you have many elements that need this directive, here is another performance-optimized solution. (Example list with 100 + lines, each with this directive)

This will always contain only one receiver $ document

 angular.module('app').directive('clickElsewhere', ['$document', function ($document) { return { link: function postLink(scope, element, attr) { var elsewhere = true; element.on('click', function(e) { elsewhere = false; $document.off('click', clickElsewhere); $document.on('click', clickElsewhere); }); var clickElsewhere = function() { if (elsewhere) { scope.$apply(attr.clickElsewhere); $document.off('click', clickElsewhere); } elsewhere = true; }; } }; }]); 

The problem with the Max Bates solution is that all directives add a listener for $ document.on ('click', function (...)); An event that causes performance issues.

The problem with the accepted answer was indicated by Max Bates.

+7
Jun 18 '14 at 8:46
source share

Found anwser in this post.

Directive

 app.directive('documentClick', function ($document, $parse) { var linkFunction = function ($scope, $element, $attributes) { var scopeExpression = $attributes.documentClick; var invoker = $parse(scopeExpression); $document.on('click', function (event) { $scope.$apply(function () { invoker($scope, { $event: event }); }); }); }; return linkFunction; }); 

Controller:

 app.controller('PageCtrl', function ($scope) { $scope.click = function (e) { if (!$(e.target).is('.language')) { //do stuff } }; }); 

View:

 <body ng-controller='PageCtrl' document-click='click($event)'></body> 
+3
Oct 17 '12 at 10:17
source share

Here is an option based on the Max solution, but more natural in terms of standard angular event directives:

 app.directive('clickOut', function($document) { return { restrict: 'A', scope: { clickOut: '&' }, link: function (scope, element) { var handler = function(event) { if (!element[0].contains(event.target)) { scope.$apply(function () { scope.clickOut({ $event : event }); }); } }; $document.on('click', handler); scope.$on('$destroy', function() { $document.off('click', handler); }); } }; }); 

Using

 <div click-out="myFunction()"></div> 

Click event passing

 <div click-out="myFunction($event)"></div> 
+2
Apr 08 '15 at 7:07
source share

The easiest way is to check the area of ​​the element. $ id and clickScope. $ id (target area of ​​the click event. $ id).

 link: function(scope, element, attrs) { //close element when mouse click outside var documentClickHandler = function(event) { var clickScope = angular.element(event.target).scope(); if (clickScope.$id != scope.$id) { //clickScope.$parent is for clicking on the directive children scope if(clickScope.$parent === null || clickScope.$parent.$id != scope.$id){ //Click everywhere but on this element //Do anything you want here, like close your element; } } }; $document.on('click', documentClickHandler); scope.$on('$destroy', function() { $document.off('click', documentClickHandler); }); } 
+1
Aug 22 '16 at 10:26
source share

The advantage of this solution:

  • You only need to bind to $(document) . Other event triggers will depend on $emit events.
  • You can use both the click-elsewhere="show=false" and click-elsewhere="fn()" expressions, thanks to $parse .

the code:

 // broadcast click event within AppCtrl app.controller('AppCtrl', function($rootScope) { $(document).on('click', function(e) { // use $emit so the event stays inside $rootScope $rootScope.$emit('click', {target: e.target}); }; }; app.directive('clickElsewhere', function($rootScope) { return { restrict: 'A', compile: function($element, attr) { // store fn in compile so it only execute once var fn = $parse(attr['clickElsewhere']); return function(scope, element) { var offEvent = $rootScope.$on('click', function(event, target) { if ( (element.find($(target)).length) || element.is($(target)) ) return; scope.$apply(function() { fn(scope, {$event: event}); }); }); scope.$on('$destroy', offEvent); }; } }; 

Usage in HTML:

  • click-elsewhere="fn()"
  • click-elsewhere="show=false"
0
Nov 10 '14 at 2:51
source share

maybe a little out of context, but you can classify (for example, “selected”) all selected elements and when the user clicks on the “do not click here” element, you can declassify all elements that are currently classified as “selected” and classify a specific element ...

-one
Oct 17
source share



All Articles