What happens with the handlers when you change the innerHTML property - javascript

Ok lets say I have
<div id="container"/>
and I put a button in this container with id = "button". Then I make .click handler for it
$("#button").click(function() {
foo();
}
Then I change the innerHTML of the div like this:
$("#container").html = "<h1> Foo </h1>";
Then I set timer for let's say 5 seconds that after that will execute the following code :
function(){
$("#container").html = "<button id="button" type="button">Click Meh!</button>"
$("#button").click(function() {
foo();
}
}
My question is: The first button was "destroyed", so was the first .click() handler for it destroyed too? Or the second .click() will just make a second handler for the same button and if I want to have only 1 handler I have to use $("#button").off("click") before calling the second .click() ?

Yes, when you removed the element (by overwriting the html of the element), you've disassosciated the click handler with the element.
Instead, we should just be looking at delegating the event. We target a static parent element (like container), and delegate the event to it:
$('#container').on('click', '#button', foo);
Now when the button is clicked, we'll fire off the foo function. Even if you remove the button and add it later, the event will still be delegated to '#container'.

Yes once you deleted the button the first handler will also destroyed because you are using ".click()" function. You no need to explicitly remove that click handler.
or else use the below ".on" function then you no need to write the function again and again. it will check dynamically adding elements and attach the events.
$( "body" ).on( "click", "#button", function() {
foo();
});

If your question is if you have to re-bind the onclick handlers when the dom changes, the answer is yes.
If you're asking what happens to the handler function, my guess is it will get garbage collected when the node gets deleted, if you want to avoid the creation of several functions, just write the handler as named function, and use that instead of anonymous one..
If you're asking whether the handler will get bound twice: it will get bound to whatever is in the selection result, if the first button exists when you run the .click then it will, though #id only returns 1 node so, it will bind to the first #button it finds, regardless of if it's already bound...

Related

jQuery won't listen for my second click

i'm trying to register the second click on a link, by adding a new class and finding it with jQuery. But it won't change the class after the 1st click.
Hope it makes sense and thank you in advance.
// Listen for when a.first-choice are being clicked
$('.first-choice').click(function() {
// Remove the class and another one
$(this).removeClass('first-choice').addClass('one-choice-made');
console.log('First Click');
// Some code goes here....
});
// Make sure the link isn't fireing.
return false;
});
// Listen for when a.one-choice-made are being clicked
$('.one-choice-made').click(function() {
// Remove the class and another one
$(this).removeClass('one-choice-made').addClass('two-choice-made');
console.log('Second Click');
// Some code goes here....
});
// Make sure the link isn't fireing.
return false;
});
At load, .one-choice-made does not exist, so when you call $('.one-choice-made'), it returns an empty jQuery object, hence the click() handler is not added to anything.
What you want to do is attach the handler to something that will always exist, which will respond to the click event (i.e. a parent/ancestor element). This is what $.on() will do for you when called in a delegated handler syntax (i.e. with a filter selector):
$(document).on('click', '.one-choice-made', function() {
// my second function
}
In this case, jQuery attaches a special handler to document, which watches for click events that propagate to it from children elements. When it receives a click, jQuery looks at the target of the click and filters it against the selector you provide. If it matches, it calls your function code. This way, you can add new elements with this class at any time, as long as they are children of the elements from the selector(s) you applied .on() to. In this case, we used document, so it will always work with new elements.
You can pare this down to a known permanent parent element to reduce click events, but for simple cases document is fine.
NOTE: In the same way, removing the class first-choice will not have any affect on whether the first click handler is called, because the handler is applied to the element. If you remove the class, the element will still have the handler. You will need to use a delegated handler for that as well:
$(document).on('click', '.first-choice', function() {
// my first function
}
Demo: http://jsfiddle.net/jtbowden/FxqX9/
Since you're changing the class you need to use .on()s syntax for delegated events.
Change:
$('.one-choice-made').click(function() {
to:
$(document).on('click', '.one-choice-made', function() {
Ideally you want to use an element already in the DOM that's closer than document, but document is a decent fallback.

jQuery event delegation

I need some help with the callbacks. For some reason, they don't work really well.
I'm making a game with jQuery. I have a <div id='button'></div> for all the buttons that are going to be in the game. The game is going to have two buttons that make actions, and a question on top of it. The question is controlled by a <h3 id='text'></h3>. What I want to know, is that for some reason I can't set callback functions to the button's ID's. In example,
I'd have the yes or no, that have their own id's set through jQuery like this:
$('#button').html('<button id='yes'>Yes</button><button id='no'></button>');
But for some reason, I would be able to set this:
$('yes').click(function(){
//function I would want
});
Of course, that's not what my code has, that was just an example. Here's the real code:
$(document).ready(function(){
$('#main,#batman,#car,#cop,#hobo,#knife,#gangfight,#ganggun,#gangknife,#blood,#hr').hide(-100);
var hr=$('#hr');
var main=$('#main');
var batman=$('#batman');
var car=$('#car');
var hobo=$('#hobo');
var cop=$('#cop');
var knife=$('#knife');
var gangfight=$('#gangfight');
var ganggun=$('#ganggun');
var gangknife=$('#gangknife');
var blood=$('#blood');
var text=$('#text');
var button=$('#button');
$('#start').html('Are you ready to play?');
$('#button').html('<button id="yes">Yes</button><button id="no">No</button>');
$('#yes').click(function(){
$('#yes,#no').hide(function(){
$('#start').hide();
main.fadeIn(-100);
hr.fadeIn(-100,function(){
text.delay(1000).html("You were just wandering around in the streets of new york, when suddenly.. You see batman!! You've never really liked him, what do you do?")
button.html('<button id="fight">Fight</button><button id="leave">Leave</button>',function(){
batman.fadeIn(1000);
$('fight').click(function(){
});
$('leave').click(function(){
text.fadeOut(function(){
text.text('Good call. As you leave, you encounter a hobo. What do you do?');
});
});
});
});
});
});
$('#no').click(function(){
$('#yes,#no').hide();
$('#start').text('Oh, okay then. Come back later!');
});
});
I'm just wondering.. How can I set callback functions to the 'fight' and 'leave'.
If you're wondering why there's all these variables at the start, those are just the images and characters.
You can't set a click handler on an element that doesn't exist. What you should do is use .on to bind a element further up the tree. Something like:
$("#someparentelement").on("click", "#yes", function() {
// your code
});
Which version of jQuery are you using? You should probably use jQuery.on() in this situation since your click handler code probably gets executed before the button is actually available in the DOM.
$("#button").on("click", "#yes", function (event) {
// Your yes-button logic comes here.
});
For more details and possibilities, read about the .on(events [, selector ] [, data ], handler(eventObject)) method in the jQuery documentation:
If selector is omitted or is null, the event handler is referred to as direct or directly-bound. The handler is called every time an event occurs on the selected elements, whether it occurs directly on the element or bubbles from a descendant (inner) element.
When a selector is provided, the event handler is referred to as delegated. The handler is not called when the event occurs directly on the bound element, but only for descendants (inner elements) that match the selector. jQuery bubbles the event from the event target up to the element where the handler is attached (i.e., innermost to outermost element) and runs the handler for any elements along that path matching the selector.
In this case, you want to delegate the event since your element is not yet available in the DOM when you're binding the event.
Don't use the click(), use on('click') and attach it to the document.
Creating a handler this way, will ensure that any new elements will be able to trigger the event.
$('fight') selects fight tag, not the tag with fight id. Try to use $('#fight') instead.

Does jQuery overwrite event listeners?

I've got a bunch divs which each contain a remove link attached with the click event below:
var observeRemoveRoom = function
$('.remove_room').click(function(){
$(this).parent().removeClass('active');
});
}
Clicking it removes the 'active' class of the parent (the div). I call this observeRemoveRoom function on window load which works fine.
The thing is, I have another function which adds more of the same divs. Since the a.remove_room links contained within the new divs weren't around on window.load I need to call observeRemoveRoom.
Am I somehow duplicating the event handlers? Does jQuery overwrite them? If so should I unbind the handlers?
Each time you call observeRemoveRoom jQuery will add a new unique event handler function for a click event.
So yes, you need to .unbind() either all currently bound handlers by just calling .unbind() without arguments, or be specific and pass in a function reference.
You can try a live query to keep them updated: http://docs.jquery.com/Plugins/livequery
Yes, you will be duplicating the event-handlers if you call observeRemoveRoom again, but it might not be noticeable since you are only calling the removeClass method which does nothing if the class is not found, which would be the case after the first listener is triggered.
Instead you can un-bind and re-bind the click event each time, like:
var observeRemoveRoom = function(){
var remove_class = function(){
$(this).parent().removeClass('active');
};
$('.remove_room').off('click', remove_class).on('click', remove_class);
}
But that said, it is recommended that you do this outside this function`, rather than binding and unbinding the event every time, like:
$(document).ready(function(){
var remove_class = function(){
$(this).parent().removeClass('active');
};
// If the element exists at dom ready, you can bind the event directly
$('.remove_room').on("click", remove_class);
// If the element is added in dynamically, you can [delegate][1] the event
$('body').on("click", '.remove_room', remove_class);
// Note: Although I've delegated the event to the body tag in this case
// I recommend that you use the closest available parent instead
});
http://api.jquery.com/on/#direct-and-delegated-events : [1]

Why do you have to pass the event object as a parameter?

I'm learning how to manipulate events in JavaScript and I'm wondering "why do you have to pass the event object as a parameter (argument) into a function when using event handling?"
Here's an example of what I am talking about:
<script type="text/javascript">
document.getElementById('button_1').onclick = (function (event) {
alert("The event is: " + "on" + event.type);
});
</script>
I wrote the code above and I pretty much understand what it does. I just don't understand the whole (event) passing. I thought of this as a way of assigning an anonymous function to the button_1.onclick event handler. Does the event handler try to pass in an event before it gets assigned or?... I'm having a difficult time understanding this. If someone could please clarify this for me I would be grateful.
[I tried searching it on Google but found very complex explanations and examples. Only a simple-to-intermediate explanation would help.] =)
The Ever-Present Event, Whether You Like it or Not
The event is always present, even when you don't provide a name:
$(".foo").on("click", function(){
alert( arguments[0].type );
});
That is the same as saying this:
$(".foo").on("click", function(event){
alert( event.type );
});
The event object is already being passed to your callback (whether your provide a name for it or not), you can choose to not use it if you like. For instance, if we looked to a jQuery onClick method:
$(".foo").on("click", function(){
/* Do stuff */
});
Making Use of It
You'll note that I have no event object referenced in my callback. I'm not required to. However, if I want to use it, for whatever purpose, I should give it a name:
$(".foo").on("click", function(myEvent){
myEvent.preventDefault();
myEvent.stopPropagation();
});
Now that I have granted myself access to the event details, I can prevent the default behavior that would result from the event, and I can also stop the event from bubbling up the DOM to other elements.
Practical Example
Suppose we wanted to listen for click events on an element:
$("#bigSquare").on("click", function(event){
/* Do something */
});
Click events happen on an element when you click the element itself, or any of its children. Now suppose this element had two children:
<div id="bigSquare">
<div id="redSquare"></div>
<div id="blueSquare"></div>
</div>
Clicking any of these, the big square, the red square, or the blue square will cause the "click" event on the big square - after it causes the click event on whichever element you clicked first (events bubble up the DOM).
We could determine which element was the target in any click event via the event itself:
$("#bigSquare").on("click", function(event){
alert( event.target.id );
});
Note here how we're accessing the ID of the target that raised the event. If you click on the red square, when that event bubbles up to the big square, we will see alerted "redSquare". The same goes for the blue square. If you click that, the event will bubble up to the big square and we will see alerted "blueSquare".
You can test this online via the following demo: http://jsbin.com/ejekim/edit#javascript,live
Try clicking the orange, red, or blue square to see what is alerted.
You are not passing the event parameter anywhere. You are just making a function that takes one parameter, called event.
When the browser calls the event handlers, it calls the function(s) assigned to it, and passes the event object to it as the 1st parameter.
P.S. You don't need the () around your function.
document.getElementById('button_1').onclick = function (event) {
alert("The event is: " + "on" + event.type);
};
You aren't passing an event into the function, you are naming the first parameter passed to your function event.
The browser is the one that is going to call your function and it passes an event object when it calls your function. You can choose not to name that parameter function(){} but the browser is still going to pass the event object in, you can use it or not use it as you see fit.
Simply put, the Event object passed to a handler contains details about the event. For example, a KeyboardEvent contain info about the key pressed, the corresponding character, and any modifier keys (alt, shift, control, meta) that were held down.
Does the event handler try to pass in an event before it gets assigned or?
The handler is your function, so it's the receiver of event, not the passer.
The event handler is bound when you assign it to the element's onclick property (or by calling addEventListener, the modern, preferred method), which is before the handler is invoked.
The Event object is passed when the handler is invoked, which is when the event fires.
So, when a user clicks on your #button_1, this causes a "click" event to fire on the button, which invokes the button's "click" handler, which is passed a MouseEvent.
For more information, read about event-driven programming.
To add to the others answers and comments, your code will not work with IE. For cross-browser capability, you need to test the existence of the first argument:
<body>
<button id="button_1">Click Me!</button>
<script type="text/javascript" >
document.getElementById('button_1').onclick = (
function(event) {
var e = event ? event : window.event;
alert("The event is: " + "on" + e.type);
});
</script>
</body>

How to remove all click event handlers using jQuery?

I'm having a problem. Basically, when a user clicks an 'Edit' link on a page, the following Jquery code runs:
$("#saveBtn").click(function () {
saveQuestion(id);
});
By doing this, the onClick event of the save button calls the saveQuestion() method and passes on the ID of the question for which the 'Edit' link was clicked.
But if in the same session the user clicks edit on 2 questions, then instead of overwriting the previous click event handler, it instead causes 2 event handlers to run, one which might call saveQuestion(1) and the other might call saveQuestion(2). By doing this 1 question overwrites the other.
Is there a way to remove all previous click events that have been assigned to a button?
You would use off() to remove an event like so:
$("#saveBtn").off("click");
but this will remove all click events bound to this element. If the function with SaveQuestion is the only event bound then the above will do it. If not do the following:
$("#saveBtn").off("click").click(function() { saveQuestion(id); });
Is there a way to remove all previous click events that have been assigned to a button?
$('#saveBtn').unbind('click').click(function(){saveQuestion(id)});
$('#saveBtn').off('click').click(function(){saveQuestion(id)});
If you used...
$(function(){
function myFunc() {
// ... do something ...
};
$('#saveBtn').click(myFunc);
});
... then it will be easier to unbind later.
$('#saveBtn').off('click').on('click',function(){
saveQuestion(id)
});
Use jquery's off and on

Categories

Resources