Add click event to element, but not its children in angular - javascript

I know this can be done with jQuery as shown here: How to have click event ONLY fire on parent DIV, not children?
$('.foobar').on('click', function(e) {
if (e.target !== this)
return;
alert( 'clicked the foobar' );
});
But in angular, this keyword is not binded to the element when I use something like:
<div ng-dblclick="ctrl.doubleClickHandler($event)">
parent, event should fire here.
<div>child, event should not fire here.</div>
</div>
and in my controller:
this.doubleClickHandler = doubleClickHandler;
function doubleClickHandler(event) {
console.log(this); // this binds to controller
console.log(event);
}
The event fires, but I need to prevent it from firing when I click on the element's children.
I don't want to hardcode a check on the event.target based on class or attribute because it might change later. Is there anyway to achieve this within the HTML tag, or in JavaScript without hardcoding the element's class or attributes (similar to the technique of binding the this keyword in jQuery)?

You can compare target and currentTarget. The former is the clicked element and the latter is the element with the handler.
function doubleClickHandler(event) {
if (event.target !== event.currentTarget) return;
// do something
}

I think you could try something like this:
<div ng-dblclick="ctrl.doubleClickHandler($event) $event.stopPropagation()">
reference: What's the best way to cancel event propagation between nested ng-click calls?

If your using jquery try this,
<div class="foobar"> .foobar (alert)
<span>child (no alert)</span>
</div>
$('.foobar').on('click', function(e) {
if (e.target !== this)
return;
$scope.myFunc(e);
});
$scope.myFunc = function(e) {
$scope.clicked = "Parent Cicked";
$scope.$apply();
};
DEMO
surely its not leading to a good programmatic skills. Hence you can try below example with angular and JS
<div class="foobar" data-parent="true" ng-click="myFunc($event)"> .foobar (alert)
<span>child (no alert)</span>
</div>
// add data attribute as data-parent="true"
$scope.myFunc = function(e) {
if (! e.target.hasAttribute('data-parent'))
return;
$scope.clicked = "Parent Cicked";
};
//if clicked element has `data-parent` property do the things.
DEMO

i update the answer by create directive with jquery in your sample.
var app = angular.module("app", []);
app.controller("controller", function ($scope) {
var ctrl = this;
ctrl.doubleClickHandler = function () {
alert("parent clicked")
}
});
app.directive("directiveName", function () {
return {
restrict: "A",
scope: {
click: "&"
},
link: function (scope, element, attr) {
element.on('click', function (e) {
if (e.target !== this) {
return;
} else {
scope.click()
}
});
}
}
})
.foobar span {
background: red;
}
<!DOCTYPE html>
<html ng-app="app" ng-controller="controller as ctrl">
<head>
<title></title>
</head>
<body>
<div click="ctrl.doubleClickHandler()" directive-name class="foobar">
parent
<span>
child
</span>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</body>
</html>

Related

How to unbind an keyboard short cut events in angular js

I created an angular directive that binds the keyboard short cut. However, once this is bind, it keeps the binding for all other divs. But i have attached only to one div. How do i unbind it after it executes and re bind when the user clicks within that div.
ex:
angular.module('Dummy').directive('keypressEvents',
function ($document, $rootScope) {
return {
restrict: 'A',
link: function () {
$document.bind('keydown', function (e) {
if ((e.which == '115' || e.which == '83' ) && (e.ctrlKey || e.metaKey)){
$rootScope.$broadcast('Ctrl+s');
}
});
}
} });
in controller
$rootScope.$on('Ctrl+s', function (e) {
$scope.$apply(function () {
$scope.doDummyAction();
});
});
in html
<div keypress-events>this is a div that binds keyboard shortcut</div>
<div>Another div which doesn't need a short cut key</div>
Appreciate any suggestions.
Don't use $document. The link function gets a scope and the element it's applied to passed to it.
link: function(scope, iElem){
iElem.bind(...
}
When you bind to the document it is listening to events that bubble out the document (page). If you just bind to the element itself you'll only get the event handler triggered when that element has focus and the event occurs.

$(".class").on('click', function () but not if it has $('class2') (child class)

I am working on a project where I need to have an onclick function for $(.playbox') but not if $('mp3buy') is pressed $(.mp3buy') is child of $('.playbox') so if I click $('mp3buy') its as if I click $(.playbox')
I have tried:
$(".playbox").not('mp3buy').on('click', function ()
and I also tried putting the following if statement within the function but then the function wont perform:
$(".playbox").on('click', function () {
if (this.hasClass('mp3buy')){
//do nothing
} else {
$(".playerbottom").removeClass("noclick");
$(".inlinethinger").removeClass("noclick");
var key = $(this).find(".play").attr('key');
var name = $(this).find(".play").attr('name');
window.nowplay = $(this).find(".play");// variable for now playing class .play
window.nowplay2 = $(this);
EvalSound(this, key);
$(".play").not(this).removeClass("pause");
$(".play").not(this).parent().parent().removeClass('playboxplaylight');
$(".play").not(this).parent().removeClass("greenback");
$(this).find(".play").toggleClass("pause");
$(this).find(".play").parent().parent().toggleClass('playboxplaylight');
$(this).find(".play").parent().toggleClass("greenback");
$(this).find(".play").hasClass("pause") ? $(".playerbottom").addClass("pausebottom") : $(".playerbottom").removeClass("pausebottom");
$(".nowplayingname").text(name);
$(".playerbottom").on('click', function () {
$(this).find(".play").hasClass("pausebottom") ? nowplay.addClass("pause") : nowplay.removeClass("pause");
});
}
});
I am wondering if there is a simple way to rule out a child class within an onclick function?
If I'm reading this right, you have this HTML structure:
<div class="playbox">
<div class="mp3buy">
... content ...
</div>
</div>
You can set a handler on .mp3buy and make use of event.stopPropagation().
$(".mp3buy").on("click", function(ev) {
ev.stopPropagation();
// Any clicks on .mp3buy will not be passed to .playbox's click handler.
});
$(".playbox").on("click", function() {
// Normal functionality here
});
$(".mp3buy").on("click", function(ev) {
ev.stopPropagation();
alert("mp3buy click handler called");
});
$(".playbox").on("click", function() {
alert("playbox click handler called");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="playbox">
.playbox content
<div class="mp3buy">
.mp3buy content
</div>
</div>
My proposal is to test the event target element against your class:
$(function () {
$(".playbox").on('click', function (e) {
if ($(e.target).is('.mp3buy')) {
// do nothing
return;
}
// do your stuff
alert('ok');
});
});
<script src="http://code.jquery.com/jquery-1.12.1.min.js"></script>
<div class="playbox" style="width: 300px;height: 300px;border:1px solid black;">
<button class="mp3buy" style="position:relative;top: 40%;left: 40%;">ClickMe</button>
</div>

How to compare angular element with jQuery element

I need to implement click outside to hide dropdown inside directive, So I have this code:
$(document).click(function(e) {
var selector = $(e.target).closest('.time-selector');
if (!selector.length) { // || !selector.is(element)) {
if ($scope.$$phase) {
$scope.show = false;
} else {
$scope.$apply(function() {
$scope.show = false;
});
}
}
});
but it don't work (don't hide) when I click on different .timer-selector element, I've try to test if !selector.is(element) but this don't work.
So How can I test if my jQuery selected element is the same DOM node as angular directive element?
Don't know if that's relevant but my directive don't have replace.
Found solution, in my case, my element is my directive tag and not .time-selector, so this code solve the problem:
$(document).click(function(e) {
var selector = $(e.target).closest('.time-selector');
if (!element.find('.time-selector').is(selector)) {
if ($scope.$$phase) {
$scope.show = false;
} else {
$scope.$apply(function() {
$scope.show = false;
});
}
}
});
Try this:
$(document).click(function(e) {
var selector = $(e.target).closest('.time-selector');
if (!selector.length) { // || !selector.is(element)) {
// adjust this line here to get the scope where .show is defined
var $scope = selector.scope();
$scope.$apply(function() {
$scope.show = false;
});
}
});
This may or may not work depending on whether selector.scope() returns the scope where 'show' is defined. If this does not work, then find the element that defines the scope where 'show' is defined, and call .scope() on the jQuery element to get the scope.
It would be interesting what exactly "element" contains. If it is something like
<div id="foo"></div>
you may check for inequality with
selector[0] != element
$jQueryObject[index] returns the appropriate HTMLElement.

html div onclick event

I have one html div on my jsp page, on that i have put one anchor tag, please find code below for that,
<div class="expandable-panel-heading">
<h2>
<a id="ancherComplaint" href="#addComplaint"
onclick="markActiveLink(this);">ABC</a>
</h2>
</div>
js code
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
alert('123');
});
function markActiveLink(el) {
alert($(el).attr("id"));
}
here I when I click on div I got alert with 123 message, its fine but when I click on ABC I want message I want to call markActiveLink method.
JSFiddle
what is wrong with my code? please help me out.
The problem was that clicking the anchor still triggered a click in your <div>. That's called "event bubbling".
In fact, there are multiple solutions:
Checking in the DIV click event handler whether the actual target element was the anchor
→ jsFiddle
$('.expandable-panel-heading').click(function (evt) {
if (evt.target.tagName != "A") {
alert('123');
}
// Also possible if conditions:
// - evt.target.id != "ancherComplaint"
// - !$(evt.target).is("#ancherComplaint")
});
$("#ancherComplaint").click(function () {
alert($(this).attr("id"));
});
Stopping the event propagation from the anchor click listener
→ jsFiddle
$("#ancherComplaint").click(function (evt) {
evt.stopPropagation();
alert($(this).attr("id"));
});
As you may have noticed, I have removed the following selector part from my examples:
:not(#ancherComplaint)
This was unnecessary because there is no element with the class .expandable-panel-heading which also have #ancherComplaint as its ID.
I assume that you wanted to suppress the event for the anchor. That cannot work in that manner because both selectors (yours and mine) select the exact same DIV. The selector has no influence on the listener when it is called; it only sets the list of elements to which the listeners should be registered. Since this list is the same in both versions, there exists no difference.
Try this
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
alert('123');
});
$('#ancherComplaint').click(function (event) {
alert($(this).attr("id"));
event.stopPropagation()
})
DEMO
Try following :
$('.expandable-panel-heading').click(function (e) {
if(e.target.nodeName == 'A'){
markActiveLink(e.target)
return;
}else{
alert('123');
}
});
function markActiveLink(el) {
alert($(el).attr("id"));
}
Here is the working demo : http://jsfiddle.net/JVrNc/4/
Change your jQuery code with this. It will alert the id of the a.
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
markActiveLink();
alert('123');
});
function markActiveLink(el) {
var el = $('a').attr("id")
alert(el);
}
Demo
You need to read up on event bubbling and for sure remove inline event handling if you have jQuery anyway
Test the click on the div and examine the target
Live Demo
$(".expandable-panel-heading").on("click",function (e) {
if (e.target.id =="ancherComplaint") { // or test the tag
e.preventDefault(); // or e.stopPropagation()
markActiveLink(e.target);
}
else alert('123');
});
function markActiveLink(el) {
alert(el.id);
}
I would have used stopPropagation like this:
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
alert('123');
});
$('#ancherComplaint').on('click',function(e){
e.stopPropagation();
alert('hiiiiiiiiii');
});
Try out this example, the onclick is still called from your HTML, and event bubbling is stopped.
<div class="expandable-panel-heading">
<h2>
<a id="ancherComplaint" href="#addComplaint" onclick="markActiveLink(this);event.stopPropagation();">ABC</a>
</h2>
</div>
http://jsfiddle.net/NXML7/1/
put your jquery function inside ready function for call click event:
$(document).ready(function() {
$("#ancherComplaint").click(function () {
alert($(this).attr("id"));
});
});
when click on div alert key
$(document).delegate(".searchbtn", "click", function() {
var key=$.trim($('#txtkey').val());
alert(key);
});

jQuery, trigger, bind, strange parameter

I have the following code:
<body>
<form>
<input type="text"/>
</form>
<script>
$( function () {
$(document).bind("EVENT", function (event, element) {
console.log("BIND", element, event);
});
$("form").each( function iterate(index, element) {
console.log("BEFORE BIND", element);
$(document).trigger("EVENT", element)
});
})
</script>
</body>
I expect that the element that I pass to the TRIGGER is the same as I get at the BIND;
but no!
BEFORE BIND: this's the FORM, as it's expected.
BIND: this is the INPUT box, no idea why.
Is it a bug or am I missing something?
If I understand your question correctly this should be what you are looking for:
$(function () {
$(document).bind("EVENT", function (e) {
console.log('bind',
e.target // this is the DOM element that triggered the event
// the form in this case
e);
});
// Triggering can be simplified a lot
$('form').trigger('EVENT');
});
The jQuery trigger documentation says that extra parameters should be passed in an array. So:
$(document).trigger("EVENT", [ element ])

Categories

Resources