Meteor Event Selectors for more complex events - javascript

I am trying to get a event handler in meteorjs to work as expected:
The White box should be clickable, if it is clicked, I need to call a function that closes or opens a chapter
when clicking the greyish text (which is a contenteditable <div>) you should be able to edit that contenteditable and has a class .editable
My Problem: I have declared an event handler like this:
Template.chapterBox.events:
'click .chapter-box': (e) ->
do_some_stuff()
how would it be possible to prevent that above event handler from firing when I click the contenteditable to edit it?
I already about something like this in the first line of the event handler
if $(e.target).hasClass("editable"):
return;
but it did not work

You can do something like this:
<template name="ChapterBox">
<div class="chapter-box">
<div class='editable'>Text</div>
</div>
</template>
Template.ChapterBox.events({
'click .chapter-box': function (event, template) {
event.stopPropagation();
console.log("clicked chapter-box: ", event.currentTarget);
},
'click .editable': function(event,template){
event.stopPropagation();
console.log("clicked editable: ", event.currentTarget);
}
});
Check this MeteorPad for a working example.
Event.stopPropagation() prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.

I had the same problem, this worked for me:
if (e.target.className == "editable") {
console.log("clicked editable");
} else {
console.log("clicked chapter-box");
}

Related

How does $(this) know what my target is?

How does $(this).keyup know I want the keyup listener associated with the #searchString input, and not the parent div? Doesn't $(this) represent the parent div? I dumped out $(this) to the console, and it looks like an object for the parent div.
Long story short:
How is this working? $(this).keyup
Instead of explicitly saying: $('#searchString').keyup ??
$('<div id="msg">' + <input id="searchString" name="searchString" type="text" value="" /> + '</div>').dialog({
open: function () {
$(this).keyup(function (e) {
if (e.keyCode == $.ui.keyCode.ENTER)
$('#btnFind').click();
return false;
})
},
buttons: [
{
text: "Find",
id: "btnFind",
icon: "ui-icon-search",
click: function () {
//do stuff
}
}
]
});
Did some testing; here are my observations:
$(this) is representative of the parent <div id="msg">
$(this).keyup is targeting any (and all) extra inputs I add to <div id="msg">
I don't think this this is event bubbling/capturing (the listeners are not nested):
$('#btnFind').click(); is an action nested inside the keyup listener
the jQuery UI dialog button id: "btnFind" has a separate event listener, outside of the the parent <div id="msg">
I went ahead and explicitly indicated the target for the listener: $('#searchString').keyup
Who cares?
Well, I didn't think you could establish event listeners on inputs via the dialog open event. I'm creating my dialog on-the-fly, and my assumption was that the input may not exist while the open event was trying to establish the event listener.

Detect click event in any nested element of an specific div

I need to be able to detect any click that happens within a specific container referenced by class, if the user clicks on any of the nested elements I should be able to detect the click and update a flag
<div class="container" >
<div class="x1">
<div class="x2">
<div class="">
<span class="">
<ul class="">
</div>
</div>
I tried using jquery but I prefer to do it using backbone.
//$(document).on('click','.container', function(e){
//$('.container').delegate("div", "click", function(e) {
Not sure what event I need to use when the users are clicking in some of the nested elements within the div that have the container class. Basically, I need to update a flag in case of the user clicks outside of this div, but I don't want to have a large scope on the event handler that listens to the whole body.
Since you asked for a Backbone example, here's how to listen to clicks on a div and its children.
var View = Backbone.View.extend({
className: "my-test-view",
template: '<div class="container"><div class="x1"><div class="x2">test</div></div></div>',
events: {
'click .container': 'onClick',
},
render: function() {
this.$el.empty().append(this.template);
return this;
},
onClick: function(e) {
console.log("clicked on", e.target, " triggered from ", e.currentTarget);
},
});
var view = new View();
$("body").append(view.render().el);
Clicking the test text should output:
clicked on <div class=​"x2">​test​</div>​ triggered from <div class=​"container">​…​</div>​
With jQuery, the above is (roughly) the equivalent to:
$('.my-test-view').on('click', '.container', function(e) {
console.log("clicked on", e.target, " triggered from ", e.currentTarget);
});
But for most case, this should be enough:
$('.container').on('click', function(e) {
console.log("clicked on", e.target, " triggered from ", e.currentTarget);
});
Don't use .children().on(...) as this will create a new listener for each child and it's inefficient.
Detecting a click outside a div is quite different and there are many ways to achieve it but none is perfect.
See :
Backbone view with custom event to detect clicks outside of it
How to detect a click outside an element?
Use jQuery to hide a DIV when the user clicks outside of it
Personally, I used focus and blur events (don't forget tabindex="-1" on the element).
Maybe this?:
$(document).on('click','.container *', function(e){
console.log(e.target);
});
The great thing about jQuery is that you can use the same selectors as you would use with CSS hence I used .container * to target all elements inside the container.
I used the jquery .children() method. Check out this code pen.
var flag = 'whatever';
$(.container).children().on('click', function() {
flag = 'updated';
});
Essentially, saying for all children of whatever element is class container (div in this case) add an event handler.

Prevent click on outer li while clicking on inner link

I have some lis including a links as below
<li>
<span>SomeText</span>
<a href='someurl' class='entityDetailModal'>sometext</a>
</li>
I am using a third party library ('LightGallery') that adds click event on Li, and by Jquery I have add click event to the links to show a dialog.
The problem is when I click on link both click event will be fired,
my click event handler is
$('body').on("click", 'a.entityDetailModal', function (event) {
event.preventDefault();
event.stopPropagation();
loadDialog(this, event, '#mainContainer', true, true, false);
return false;
});
I tried event.stopPropagation() and event.preventDefault(); and return false; in link onclick event handler but they don't work.
Sample:http://jsfiddle.net/HuKab/30/
How can I overcome this?
Update
It seems the problem is the way I add click event handler,
using this way it seems that everything is ok
$('a.entityDetailModal').click(function (event) {
event.preventDefault();
event.stopPropagation();
loadDialog(this, event, '#mainContainer', true, true, false);
return false;
});
Update 2
Thanks #Huangism, this post stackoverflow.com/questions/16492254/pros-and-cons-of-using-e-stoppropagation-to-prevent-event-bubbling is explaining the reason.
Use stopPropagation(); in child element
$("li").click(function (e) {
alert("li");
});
$("a").click(function (e) {
e.preventDefault(); // stop the default action if u need
e.stopPropagation();
alert("a");
});
DEMO
It is not very clear to me what your problem really is. If you simply want to get rid of the click on the li tag you may use .unbind() from jQuery (see: http://api.jquery.com/unbind/). You should end up with only your click event.
Another thing that might help is to use something like:
$("a").on('click.myContext', function(event) {
//Your action goes here
}
This way you can have parallel events and turn them on with $("a").on('click.myContext') and off with $("a").off('click.myContext')
Edit: Use:
$("a").on('click.myContext',function (e) {
e.stopPropagation();
alert("a");
});
see working example: http://jsfiddle.net/bGBLz/4/

How to prevent default link behavior if element inside of link is clicked

I have a link that looks like this:
<a href="page.html" class="myLink">
Link text
<div class="toggle">x</div>
</a>
When they click on the x in toggle I want to prevent the link from navigating, but if they do click on the Link Text I want the link to navigate.
I tried this:
$('.toggle').click(function(event) { $(this).parents('a').preventDefault(); });
But it didn't seem to work.
To stop propagation from the clicked element to the outer a, you'd have to call stopPropagation. But here you can simply return false ( which both stops propagation and prevents default behavior) :
$('.toggle').click(function(event) {
// do interesting things
return false
});
It is the event not the element that you need to fire the preventDefault() method upon.
$('.toggle').click(function (event) {
event.preventDefault();
});
This will stop the event from triggering but not propagating up the document.
$('.toggle').click(function (event) {
event.stopPropagation();
});
Is it's counterpart.

Prevent keydown() from being captured by document binding

I'm not exactly sure how to phrase this, so I couldn't search it. Basically, I have a keydown() bind on $(document). I'd like to show() another div, and have all keydown events be rerouted to this div and prevented from firing off in the document handler. Is this even possible, or would I have to put all my main keybindings on another div and work from there?
e.stopPropagation, or
e.preventDefault (depending on the situation)
Where e is the event.
Ex:
function onKeyDown(e) {
doStuff();
e.preventDefault();
}
e.preventDefault() will prevent the default behaviour of an event. What you need is to use
e.stopPropagation(), so that the event does not bubble up the DOM structure.
$(element).keydown(function(e) {
// do the task
// allow the default behaviour also
e.stopPropagation();
//^. BUT stop the even bubbling up right here
});
e.stopProgation(), can be bit confusing to grasp on the first but I created a demo with click event to explain it.
Hope it helps!!
Try:
​$(document).on('keydown', function (evt) {
$('#foo').show().trigger(evt);
});​​​​​
$('#foo').on('keydown', function (evt) {
console.log(evt);
return false; // this is very important. Without it, you'll get an endless loop.
});
​
demo: http://jsfiddle.net/Z7vYK/
The only way I can think of to even have a keydown event run on something other than an input or document, is to manually trigger it. You could have a global variable keep track of whether or not your div is showing, then trigger the event on your div accordingly.
Here's one such solution
HTML
Show div
<div id="hiddendiv"></div>​
Javascript
var showing = false;
function showdiv()
{
showing = true;
$('#hiddendiv').show(200);
}
// Set up events on page ready
$(function() {
$(document).keydown(function(e) {
// If the div is showing, trigger it's keydown
// event and return
if(showing)
{
$('#hiddendiv').data('keydown_event', e).keydown();
return true;
}
alert('Document keydown! Keycode: ' + e.keyCode);
// Otherwise do the normal keydown stuff...
});
// Keydown for the hidden div
$('#hiddendiv').keydown(function() {
e = $(this).data('keydown_event');
alert('Hiddendiv keydown! Keycode: ' + e.keyCode);
// Make sure to stop propagation, or the events
// will loop for ever
e.stopPropagation();
return false;
});
});
​
As you can see, the #hiddendiv keydown event is being triggered by the document keydown event. I've also included a slight hack to get the event object to the hidden div using the jQuery data function.
Here's a demonstration of the code: http://jsfiddle.net/Codemonkey/DZecX/1/

Categories

Resources