I'm new to jQuery and wrote the following code. Strangely, the jQuery code somehow works even after the time delay. alert() gets called onclick after the time delay. The same thing in javascirpt with .addEventListener() would give error since the element doesn't exist. Can someone explain me how and why jQuery does this?
<div id="outerId" class="outerHolder">
<div class="innerHolder"></div>
</div>
JS Code:
$("#outerId").on("click touchstart", "#newTag", function (e) {
alert("OK");
});
setTimeout(function() {
var tag = '<div id="newTag">Hello World</div>';
$("#outerId").append(tag);
}, 5000);
Here is a jsFiddle of the same: https://jsfiddle.net/jb6pmovb/
My guess is that your query is about the way on() is binding to to the object. When on() is first ran, #newTag does not exist, so you might be wondering why it still triggers when appended after a delay.
This is because #outerId is the object being bound to, which does exist the time on() is called. When you append #newTag, it doesn't alter the outer binding, it simply looks over the children when it is clicked.
With regular js I assume you are using addEventListener, which requires you bind the event to the specific object. If you do try and use that directly on #newTag before it exists, it obviously won't work.
You can see by the docs for on():
selector
Type: String
A selector string to filter the descendants of the selected elements that trigger the event. If the selector is null or omitted, the event is always triggered when it reaches the selected element.
If you are wondering how the click works on an element which is not there at the time of page load, then that's because you are attaching the listener on the outerDiv and using .on
Check out this for the difference between using .on and .click
Related
I have a situation where a click eventlistener is being set on on a dynamic element using jQuery's .on:
$('body').on('click', '#email-me', function() {
call my code....
});
and later on in the page, I have to remove this listener - but - and here's the catch - I DON'T have access to jQuery anymore (long story), which means pure js...
so, I can't use unBind(), and even if i name my anonymous function up there, it still won't remove the event listener.
How do I remove the bind, so this element isn't clickable anymore?
Thanks for reading!
You can't. jQuery events are handled differently than normal javascript events.
When you add an event to an element with jQuery, these steps are followed:
If the element hasn't been initialized with an internal (internal to jquery) datacache, it gets initialized with a datacache, then the datacache is returned.
If this is the first event handler added for that event type, a special event is added to the element for that event type that executes jQuery.event.dispatch.
Finally, the handler(s) that you passed in are added to the datacache.
Therefore, the only way for you to remove this event is to get ahold of the special event handler that jQuery bound that triggers jQuery.event.dispatch, but since you don't have access to jQuery, there's no way you will get that event handler. (even with access to jQuery, I don't think you can get that handler.)
You need to instead find a way to retain access to jQuery, or don't use it at all.
I am using this code in my application:
document.getElementById("inventory_box").innerHTML = "<img src='./img/rock.gif' id='test' />";
The #inventory_box element is present already, so it just spews out the IMG into #inventory_box.
What I want is to be able to click this appeared IMG with id name test,
but won't work like:
$("#test").click(function() {
// Run this
});
Try this,
$(document).on('click',"#test",function() {
alert('test');
});
Read on()
Since the image is added dynamically, you need to use event delegation to register the event handler
// New way (jQuery 1.7+) - .on(events, selector, handler)
$('#inventory_box').on('click', '#test', function() {
// Run this
});
This will attach your event to test image element within the #inventory_box element,
reducing the scope of having to check the whole document element tree and increasing efficiency.
Consider using 'append' instead of innerHTML. Using a mix of vanilla JavaScript & jQuery seems to be causing some delay in updating the DOM with the new element.
The code below works for me.
$("#inventory_box").append("<img src='./img/rock.gif' id='test' />")
$('#test').click(function(d){console.log("clicked!");});
Your assignment of event handler runs before there is an element having such id, so after you create an element, it will not have any event handler assigned to it.
As it was suggested, easiest way to solve this common javascript error, you can assign event to a container DOM element and use jquery's event delegation to fire events on event newly added DOM elements.
But I rather not use this approach, the reason I can not give you, say, I just simply prefer not to.
Always assign events after element is created. for example:
document.getElementById("inventory_box").innerHTML = "<img src='./img/rock.gif' id='test' />";
immediately after this, execute this:
$("#test").click(function() {
// Run this
});
$('#inventory_box img').click(function() {
// Run this
});
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.
Following is a piece of jquery code that is driving me nuts
var count = 0;
$('#some-element-id').click(function(){
var currentElement = '#new-div-id-'+count;
$(currentElement).after($('<div id="new-div-id-'+(++count)+'">Hello World!<span class="delete_me">x</span></div>'));
});
$(".delete_me").click(function () {
alert('Deleting!');
});
Now accordingly when I click on element with id some-element-id a new div is inserted and I see the x character. But clicking x doesn't do any thing. No error. As per http://api.jquery.com/after I can insert elements this way which is working fine. I can ee the new elements in DOM tree using Firebug. Now why no event is fired when I click on span? For some unknown reason I am forced to use jQuery 1.3.2 but that should not be a problem.
Update 1
I understand that I am trying to bind an even to an element that doesn't exist in the DOM. But please note that even is not fired, the event will be fired after the element is embedded in the DOM. I used following code and even it doesn't work
$("span.delete_me").live('click',function () {
alert('Deleting!');
});
There is no error on the console.
Update 2
Here is the actual rendered code http://jsfiddle.net/8sjcZ/
See http://jsfiddle.net/vKwm6/
Use the live method:
$(".delete_me").live("click", function () {
alert('Deleting!');
});
At the time you call the .click method in your post, the "x" doesn't exist.
try
$(".delete_me").live('click',function () {
alert('Deleting!');
});
your .click() is not working because the .delete_me class is not in DOM at time you call .click() so binding never takes place. .live() ensures that binding takes place for elements which are created at runtime.
hmmm you need to do it with live()
$(".delete_me").live('click',function () {
alert('Deleting!');
});
live() will apply to dynamically added objects
http://api.jquery.com/live/
First off, I don't want another plugin to do this... jQuery already has the functionality to do 99% of what I want with the live() method.
Basically, I want to change this:
$(".some-button").live("click", function() { alert('yay!'); });
into this:
$(".some-button").live(function() { alert('yay!'); });
So, what I'm saying is that I want to fire a method right away when an element is added to the page... jQuery can already do this SOOO close because that's how it adds the "click" even in my example above!
How can I achieve this without adding another plugin, but rather, just by using the same functionality as the "live" and "die" methods do?
Here's some code I've copied and pasted that seems to work in fiddle, at least on FF: http://jsfiddle.net/KQBzn/
$(document).bind('DOMNodeInserted', function(event) {
alert('inserted ' + event.target.nodeName + // new node
' in ' + event.relatedNode.nodeName); // parent
});
source: http://forum.jquery.com/topic/how-to-get-notified-when-new-dom-elements-are-added
There isn't any cross-browser way to do this, and there's nothing in jQuery itself that allows it.
You'd have to use a plugin, or just manage invoking code for your new elements manually.
The the live()[docs] method and the delegate()[docs] method are only for event handling. The code you give them will only respond to browser events, not to DOM manipulation.
The reason .live() won't do this is because it does not run any code when adding new elements to the DOM. It isn't monitoring any DOM changes. Rather it is responding to events that bubble to the document, and invoking the handler if it matches the selector you gave it.
You can't do it with the .live() method.
It seems jQuery should add a feature to the .live() method so that if its used with a specific keyword like 'created' instead of an event name then it will let you execute a function for the created element. That'd be cool! For example, the ideal scenario would be like this:
$('.foobar').live('created', function() {
// do something with each newly created .foobar element here.
});