I want to attach a function to a jQuery element that fires whenever the element is added to the page.
I've tried the following, but it didn't work:
var el = jQuery('<h1>HI HI HI</H1>');
el.one('load', function(e) {
window.alert('loaded');
});
jQuery('body').append(el);
What I really want to do is to guarantee that another jQuery function that is expecting some #id to be at the page don't fail, so I want to call that function whenever my element is loaded in the page.
To clarify, I am passing the el element to another library (in this case it's a movie player but it could be anything else) and I want to know when the el element is being added to the page, whether its my movie player code that it is adding the element or anything else.
I want to attach a function to a
jQuery element that fires whenever the
element is added to the page.
You want the livequery plugin, which does just this. The recent live function is similar, except it won't call you when the element is added. We use it all the time-- works great.
You'll use $('h1').livequery(function() {alert('just added');});
I do not know that there is this type of event, what comes to mind is creating the event "el-load" based on this tutorial, and then extend "append" to know if the item has this event make the call to it.
Use LiveQuery (jQuery plugin), and attach a load event to ur dom element (h1), in this case.
try overwriting the append method so you can add your own event?
jQuery.extend(jQuery.fn, {
_append: jQuery.fn.append,
append: function(j) {
this._append(j);
j.trigger('append');
}
});
var el = jQuery('<h1>HI HI HI</H1>');
el.one('append', function(e) {
window.alert('loaded');
});
jQuery('body').append(el);
If the tag is being created via ajax, you can use a related node to subscribe to the ajaxSuccess event.
http://docs.jquery.com/Ajax/ajaxSuccess
$('#somenode').ajaxSuccess(function(){
if ($('h1').length > 0) { ... }
});
If it's just being added to the DOM by a local script, I'm not sure it's possible to observe it's creation, with the exception of using a timer to poll for it.
Depending upon the browsers you need to support there are DOMNodeInserted and DOMNodeInsertedIntoDocument events. Can't vouch for how well they work myself but theoretically you could bind to these events and then either check the new node and the possible subtree that was inserted, or just check the entire document again with a $(selector) of your choosing to detect the node you're waiting to see added.
Try these:
var el = jQuery('<h1>HI HI HI</H1>');
jQuery('body').append(el);
setTimeout(function(){
window.alert('loaded');
},1000);//delay execution about 1 second
or to be safe this one:
var el = jQuery('<h1>HI HI HI</H1>');
jQuery('body').append(el);
window.checker = setInterval(function(){
if($('someselector').length>0){ //check if loaded
window.alert('loaded');
clearInterval(window.checker);
}
},200);
basically, this will loop every 200ms until the selector gets result, and terminates the loop when the result is available
Related
I want to add some code by addEventListener. I would use DOMContentLoaded, but ID which I'm trying to select is not available on page load. I could use mouseover, but it iterate the code on any move. I could also use click event, but I don't want it show on click, but just when it's shown. How can I handle it?
document.addEventListener("mouseover", function(event){
document.querySelector("#id").insertAdjacentHTML('afterend', '<div>asd</div>');
});
You need to delegate
var yourSpecificId = "some-id";
document.addEventListener("mouseover", function(event){
if (event.target.id == yourSpecificId ) //only when the id of the mouseover element is matching yourSpecificId
{
//code you want to execute
}
});
I would suggest a Mutation Observer. It looks hard to implement, but it's very easy. You can provide a callback function, and then a quick if statement to check if the newly added element has the correct id. If so, run your code and disconnect the observer.
It would be easier to help you if you posted a working example of when an element is added and the function you need to run.
Read this blog: https://davidwalsh.name/mutationobserver-api
I've implemented a chat application using socket-io and nodejs. The application is running fine but, sometimes, I'm facing problems to treat HTML content because when I try to $('#id').hide() or $('#id').show() nothing happens because the element id is not available.
If I try to refresh page pressing F5, sometimes it works because that element is rendered before I try to hide or show it. I got this behavior while debugging using Google Developer tools but I'm not sure if it's the "real why".
I was trying to find on Internet what is the life cycle of DOM elements but I didn't find something that could clarify my thoughts.
I'm trying to reproduce this problem on development environment but I'm pretty far of reach the problem:
<script>
console.log('Creating socket');
var socket = io();
console.log('Socket created');
socket.on('connected', function (data) {
console.log('connected to server');
});
function timeout() {
setTimeout(function() {console.log('sleeping')}, 5000);
}
$(document).ready(function(){
timeout(); // is possible to stuck process on this point?
console.log('Ready');
});
</script>
No matter where I put socket.on('connected'.. because it's always called after console.log('Ready'). Based on this, my theory of F5 refresh is not correct and I feel that I'm running in circles.
Anyone have an idea why HTML elements are not present sometimes?
And, If I use socket.on('anyevent, {}) inside $(document).ready(function(){} do I have any guarantee that the event will only be processed after page being full rendered?
On a real world, all our sockets events are inside $(document).ready(function(){} but still not hiding or showing some html elements because they aren't present.
I am not sure about your HTML and code structure but this sounds like you are binding your event listeners to a dynamically added element but this element does not exist at the time of the binding.
If my understanding is correct, you need to add the binding on an element but base the action on the newly added element, something along the lines of:
// Add event listener, bound to the dynamically added element
$("button").on('click', $("#newElemId"), function(){
// if element exists, toggle it
if($("#newElemId").length){
$("#newElemId").toggle();
}else{
console.log('element not present yet');
}
});
See demo below:
$(function(){
// define function to add an element to the DOM
var addElement = function(){
var newElementAsObj = $(document.createElement('div'));
// add an id for querying later
newElementAsObj.attr('id', 'newElemId');
// add some text (so it's visible)
newElementAsObj.text('New Element');
$("#container").append(newElementAsObj);
console.log('new element added!');
}
// add a new element after a few secs
setTimeout( addElement, 5 * 1000); // time is in ms so 5*1000 = 5secs
// Add event listener, bound to the dynamically added element
$("button").on('click', $("#newElemId"), function(){
if($("#newElemId").length){
// if element exists, toggle it
$("#newElemId").toggle();
}else{
console.log('element not present yet');
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<button>Toggle</button>
</div>
First, regarding this:
$(document).ready(function(){
timeout(); // is possible to stuck process on this point?
console.log('Ready');
});
No, it's not possible. But you don't need to wait there. You can remove that timeout function entirely.
You should move the socket.on('connected', function ... into $(document).ready(... because you don't want to respond to any socket events until the document is ready.
<script>
console.log('Creating socket');
var socket = io(); // It's fine to do this before the document loads
console.log('Socket created');
$(document).ready(function(){
socket.on('connected', function (data) {
console.log('connected to server');
});
console.log('waiting for connection...');
});
</script>
JQuery documentation describes that you can use $(window).on('load', function() {}) to run your code after the entire page, not just the DOM, is ready. You might try that if it's not enough that only your DOM is ready, but you need to wait for the whole page to be loaded.
https://learn.jquery.com/using-jquery-core/document-ready/
If I try to refresh page pressing F5, sometimes it works because that element is rendered before I try to hide or show it. I got this behavior while debugging using Google Developer tools but I'm not sure if it's the "real why".
Are you dynamically creating that element for example with $().append() or similar? If so, make sure that you actually create the element before you try to interact with it. If the element is not created dynamically, make sure that the code that interacts with the element is inside the $(document).ready or $(window).on('load') callback.
No matter where I put socket.on('connected'.. because it's always called after console.log('Ready'). Based on this, my theory of F5 refresh is not correct and I feel that I'm running in circles.
This happens because establishing the socket connection takes more time than to render the DOM. It's generally good idea to attach the event listener as soon as possible to not miss any events. If you attach the event listener only after the DOM has loaded, you might miss some events. But be aware, that if you manipulate the DOM inside the event listener callback, then you cannot be sure that the DOM is loaded and your target element is there, unless you attach the event listener after the DOM has loaded. So I recommend to attach event listeners after the DOM has loaded. At least those that contains some code to modify the DOM.
Anyone have an idea why HTML elements are not present sometimes?
There are not many possible reasons for this. Either your elements are not yet loaded or your code has removed them for some reason. I suggest putting breakpoints to the places where you create the elements or manipulate them somehow and see what the execution order is.
And, If I use socket.on('anyevent, {}) inside $(document).ready(function(){} do I have any guarantee that the event will only be processed after page being full rendered?
You have a guarantee that the callback function will be executed when the anyevent occurs and when the DOM is ready, that is, all the static html elements are there.
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.
I need to fire a plugin on certain trigger elements.
I'm using this:
$( ':jqmData(role="page"):jqmData(trig="true")' ).live( 'pagebeforeshow',function(e){
console.log("detected");
// stuff to do...
});
Since this is my background page (first one in the DOM), using live fires it on every transition and replacing live with one only fires it on the initial trigger element and not on the 2nd element being pulled in.
Question:
How can I set up a function that is "live to trigger elements, but runs only once per trigger element found"? Would setting a flag with data help?
Thanks for infos!
I guess your dilemma is that you have to use .live(), since initially there is only 1 matching element in the DOM, rather than how they are ordered? Otherwise, .one() should work fine. The manual has a nice example for how you can implement .one() using .bind(), here is how you do it with .live(), it should do the trick:
function preparePage(e) {
$(this).die('pagebeforeshow', preparePage);
console.log("detected");
// stuff to do...
}
$(':jqmData(role="page"):jqmData(trig="true")').live('pagebeforeshow', preparePage);
Set a variable where you would store whether your trigger was already proccessed. Use this varible as condition iside your trigger to make sure that it has run only once. Then reset it when you know that your trigger can run again.
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.
});