understanding event handlers - javascript

As an exercise, I'm trying to add an event listener to an ebay.com element.
Expected result: show an alert and stop the web page from going to the next URL.
What happens: the alert is shown but the next URL is shown anyway.
I found something interesting on the product pages where I'm testing out preventDefault, stopPropagtion and stopImmediatePropagation.
No matter which combinations I use, nothing seem to work.
The basic code is:
$('#binBtn_btn').click(function(evt){
alert('hi');
evt.stopPropagation(); //or any other option.
});
The thing is that I get the alert, but it still goes to the next page, as if I never stopped the propagation.
I read a lot of articles about event handling, but I couldn't find the answer.
Your help is much appreciated.

My best guess it that the Button has its own click handler, and it's firing before yours.
$('#binBtn_btn').data("events") shows us that there is indeed a click event. Remove that using off.
$('#binBtn_btn').off('click');
Clicking the button now will still cause the form the submit, as all we're doing is browsing to a page. The button is actually just an a tag.
$('#binBtn_btn').click(function(e){
alert('Gotcha!');
e.preventDefault();
});
Let's see what happens if we remove their handler, add ours, and then re-add their one...
var existing = $('#binBtn_btn').data('events').click[0];
$('#binBtn_btn').off('click');
$('#binBtn_btn').click(function(e){ alert('foo'); e.stopImmediatePropagation(); return false; });
$('#binBtn_btn').data('events').click.push(existing);
Same, but just looking at the function for the click handler (rather than tweaking the events.click array directly...)
var existing = $('#binBtn_btn').data('events').click[0].handler;
$('#binBtn_btn').off('click');
$('#binBtn_btn').click(function(e){ alert('foo'); e.stopImmediatePropagation(); e.preventDefault(); });
$('#binBtn_btn').click(existing);
As expected, what is now the second handler -- their handler -- doesn't first. (I've added a return false; rather than e.preventDefault();, just to demonstrate different ways of doing things!)
You can check out what they're doing by placing a breakpoint and viewing the existing var above. You'll see that at the end of their function, they do indeed call e.preventDefault();.
Hope this helps.

try using evt.preventDefault() like this:
$('#binBtn_btn').click(function(evt){
evt.preventDefault();
alert('hi');
});
Then it will not go to the next page.

Related

Updating Key Event in Javascript

Hey I have a problem with a grid I am using in Javascript. I'll try tell you what I've tried first. Basically it has a key event for the button delete attached to it. However I want to override this and do something else for this specific keyup event. There is other keyevents that need to stay but I need to change what happens when the delete button is pushed when I have a row selected.
I've tried a couple of things including targeting it with bind and unbind but nothing seems to work.
I attached an alert to the delete function to fire showing what element is firing the function and it's coming back with dataGrid.
Also I tried stop propogation but no luck.
$(".divDataGrid")
.keyup(function(event) {
console.log("seamus");
event.stopPropagation();
// Do something
});
However none of this works. Has anyone out there run into a similar problem or has anyone an idea on how to fix this?
If I understand correct, you are trying to prevent the default action on button. In that case what you need to use is event.preventDefault();
event.stopPropagation(); will just stop the event from bubbling up; will not restrict its default action.

Trying to change jQuery click handler of parent fires off new click event

I'm experiencing some (to me) unexpected behavior from event listeners using jQuery, but I expect it's just the underlying Javascript functionality that's confusing me. I think there's a good chance that the answer to my problem is fairly simple, but I can't figure it out.
I have a <div> with a status in it, which is 'New' by default. I want to be able to click on that <div> and bring up a pair of buttons, one which allow you to replace the 'New' status text with 'Complete', and another which will cancel the action, removing the buttons and displaying the 'New' status text again.
I can get everything to work, and it all works fine if I use a different element to display the buttons, but when I try to temporarily replace the text in the <div>, something strange happens.
When I try to reset the original click event for the <div>, what appears to happen is that the click on the cancel button also triggers the just-set click event as well. This re-displays the buttons, so it looks like the cancel button just didn't work. (I was stuck on that for a while...)
I've made a very simple JSFiddle that shows the problem I'm having:
https://jsfiddle.net/pn1q658w/4/
And there's also a slightly modified version that shows things working as long as I've got the cancel button in a different element than the element where I'm resetting the original click function:
https://jsfiddle.net/pn1q658w/3/
I assume this has something to do with the fact that I don't completely understand the way that the timing of these events works. The same click appears to be firing off an event that is set during an action taken because of that click, which I didn't expect, but may very well be how things are supposed to work.
My question is how can I have a click event which is trying to set a click listener on a parent element not fire off the new click at the same time?
Or, if I've completely misunderstood the nature of my mistake, an indication of what I have done wrong would be much appreciated. Thank you!
UPDATED
Just like #charlietfl said, I bleive that the simplest way is to separe the elements everyone with his own class, See WORKED FIDDLE HERE :
HTML :
<div id="elementId">
<span class='text'>New</span>
</div>
JS :
$(function(){
var newBtn = '<button class="btn btn-default complete">Complete?</button><button class="btn btn-default cancel">X</button>';
//Handle the click in the text span
$("#elementId").on("click","span.text",function(e){
$(this).html(newBtn);
});
//Handle the click in the complete button
$("#elementId").on("click","button.complete",function(e){
$('#elementId').html("<span class='text'>Completed</span>");
});
//Handle the click in the cancel button
$("#elementId").on("click","button.cancel",function(e){
$('#elementId').html("<span class='text'>New</span>");
});
});
I hope that this code help you.
The problem is you rewrite alaways content of div because you don't stop propagations.
I fix your problem with this code:
var oldCellContent = $('#elementId').text();
var newButtons = '<button class="btn btn-default complete">Complete?</button><button class="btn btn-default delete">X</button>';
$("#elementId").click(function(){
$(this).html(newButtons);
});
$("#elementId").on("click","button.complete",function(e){
console.log('The complete function fired.');
$('#elementId').text('Completed');
e.stopPropagation();
});
$("#elementId").on("click","button.delete",function(e){
console.log('The cancel function fired.');
$('#elementId').text(oldCellContent);
e.stopPropagation();
});
Need to understand that when you click on an element inside another element...you are still clicking on the parent as well.
Events "bubble" or "propagate" up the DOM tree all the way to the document...unless told to stopPropagation()
What you are seeing is expected behavior.
You can prevent that bubbling by:
$(selector).click(function(event){
event.stopPropagation();
});
There are some oddities in your code that could defintiely be streamlined
First you pass an element to the handler...then take properties of that elemnt to create a selector to find exactly the same element again in the DOM
var cellId = element.id;
$('#' + cellId)
Can be simplified to
$(element);// doesn't require searching for the ID
And can also be stored as a variable instead of doing the same selector over and over
var $el = $(element);
$el.off('click');
var oldCellContent = $el.text();
These simplifications are more efficient and easier to read
The simplest solution to all of this is wrap the "New" text in it's own element and put the "show buttons" click handler on that element and simultaneously hide "new".
Code will be much simpler and there won't be any propagation issues or need to use off() and then add same handler again.

Strange behaviour using .on() for click event - Fired twice

I already checked answers about click events fired twice. But I have a question about using .on().
Usually, I use it like this on dynamically added elements, and it always worked fine:
$(document).on("click", "dynElement", function(){})
In the current website I'm working on, I use it several times. But in the function that I'm trying to achieve, let's say, a dynamic "jump to page", click on page number is triggered twice:
$(document).on("click", ".jumpTo .number", function(){
console.log("Jump");
});
Trying to find the origin of this behaviour, I tried this syntax that works fine:
$(".jumpTo").on("click", ".number", function(){
console.log("Jump");
});
Can anyone explain what is the difference between these two different syntaxes (which look quite similar to me)?
And optionally, why is $(document).on("click", ".jumpTo .number", function(){}) triggered twice? (Optionally because I am not able to reproduce this behaviour in a Fiddle, everything works as it is supposed to).
$(document).on("click", ".jumpTo .number", function(){
console.log("Jump");
});
In this case the click handler is set on the document object. So whenever you click somewhere on the page, it will fire and look for a ".jumpTo .number" element inside it. If it finds it, it will check if the click was on it and your function will execute.
$(".jumpTo").on("click", ".number", function(){
console.log("Jump");
});
Here the click handler will be on .jumpTo
As Al.G said probably this code gets executed multiple times, so you actually add that handler multiple times, hence the double firing.
One way to solve it is to do something like this:
$(".jumpTo").unbind("click").on("click"...
Another is to change your code to make sure the .on() call doesn't get executed twice.

Breaking .preventDefault()

Whenever I use preventDefault(), I typically place it at the top of the event handler, like so:
$('#foo').on('click', function(e){
e.preventDefault();
// do stuff
});
Is there any harm in placing it at the bottom of the event handler, and doing stuff before you invoke e.preventDefault()?
Another way of phrasing this question: can you be sure that, by including e.preventDefault() anywhere within the event handler, you will never follow through - say, to the target on a link or the submission of a form?
I've set up a fiddle that you can play with here: http://jsfiddle.net/tuanderful/SMdrN/
Yes.. where you place the statement is irrelevant.
As long as e.preventDefault() is called within the handler the default action will not be triggered
You can place it wherever you want, you can even call e.preventDefault(); inside some if block, it doesn't change the behavior
As long as nothing goes wrong in the code, it doesn't matter where you call preventDefault.
If you put it first in the code, it will prevent the default action even if the script crashes further on.
If you put it last in the code, it will only prevent the default action if the script didn't crash anywhere on the way.

Prevent click jump on jQuery one() function

I'm using the one() function in jQuery to prevent multiple clicks. However, when they click the element a second time, it does the annoying click jump and sends you back to the top of the page.
Is there a way to prevent this from happening? Unbinding the click and re-binding it when the function is done has the same result (and I'm assuming that one() just unbinds the event anyways).
A quick example of this happening: http://jsfiddle.net/iwasrobbed/FtbZa/
I'm not sure if this is better or not, but you could bind a simple function that maintains the return false.
jQuery provides a shortcut for this with .bind('click',false).
$('.someLink').one('click', function() {
$(this).bind('click',false);
return false;
});
or if you have several of these links, a very efficient alternative would be to use the delegate()[docs] method to bind a handler to a common ancestor that takes care of the return false; for you.
Here I just used the body, but you could use a nearer ancestor.
$('.someLink').one('click', function() {
});
$('body').delegate('.someLink','click',function(){return false;});
Try changing the href so the '#' isn't being used: http://jsfiddle.net/FtbZa/1/
$('.someLink').one('click', function() {
alert('test');
return false;
}).attr('href', 'javascript:void(0);');
You could use the standard .click() function and a little logic:
1. $('.someLink').click(function(event) {
2. event.preventDefault();
3. if (!$(this).hasClass("clicked"))
4. alert('This will be displayed only once.');
5. $(this).addClass("clicked");
});
Listen to anything with the class someLink for a .click()
Stop the browser doing what it would normally do.
Check if the object has the class clicked (Note this could be any name you wanted)
It hasn't so do something.
Add the class clicked so next time its clicked, it will ignore your code.
See the demo here
The problem is that after the listener has been unbound there is nothing stopping the browser from honoring the link (Which it is treating as an anchor tag) and trying to go to it. (Which in this case will simply lead to the top of the page.

Categories