Check to see if element exists after DOM is ready - javascript

I'm trying to detect whether an element is visible after the DOM is ready. This element is a third party widget that loads slower than the page does.
My console.log for 'dom ready' is firing - like it should, but my check to see if the element is visible is returning false, as the element loads after the dom is ready.
Is there a way to listen for elements after the dom has loaded?
<script>
$(function(){
console.log('dom ready');
if($(element).is(':visible')){
console.log('element is visible. do stuff.');
}
});
</script>

you can get the id from the iframe, or from the document that is being loaded and do something like this..
$('#external').load(function(){
//lets do something when is loaded
if($(element).is(':visible')){
console.log('element is visible. do stuff.');
}
});
This will trigger once that script, iframe is done loading

Try to read a documentation, maybe third-party widget's API allows you to attach listener on create event. That would be an ideal solution.
If it is not possible try using setTimeout function:
$(function(){
console.log('dom ready');
setTimeout(function() {
if($(element).is(':visible')){
console.log('element is visible. do stuff.');
}
}, 10);
});
If 10 ms is not enough, you may increase this interval unless it works, although I don't recommend using this approach.

Related

Using addListener to an element that would be created later

I get an error '.addListener is not a function' upon trying this:
if(document.getElementById("id")){
document.getElementById("id").addListener('click', function(){alert("ok");});
}
This element 'id' comes into picture when the entire document gets loaded, and I am using it in the middle of the documents construction. So, I did this:
window.onload = function(){
if(document.getElementById("id")){
document.getElementById("id").addListener('click', function(){
alert("ok");
});
}
}
The error is gone now, but the element 'id' does nothing upon being clicked.
How to make it clickable?
It sounds like you may be assigning to window.onload more than once. If you do this, only the last callback assigned to it will run. Use addEventListener instead, so that prior assignments to onload do not conflict with later assignments to onload.
You can also listen for DOMContentLoaded instead of load, allowing the listener to be attached faster:
window.addEventListener('DOMContentLoaded', function(){
const elm = document.getElementById("id");
if(!elm){
return;
}
elm.addEventListener('click', function(){
alert("ok");
});
});
Best to never assign to an .on- property unless you're certain it will never be assigned to again (or unless you're certain it should only ever have one listener).
Because the element is added later in the dom, you can not attach a listener this way.
What you should do is to attach a listener on the document that will 'filter' the events, so elements added later on in the dom will still be able to fire your events. Try the code below:
document.addEventListener('click',function(e){
if(e.target && e.target.id== 'id'){
//do something
}
});
Now anytime anything is clicked on the dom, this listener will await for an element with id='id' to execute your code, otherwise it will not do anything. This method is called
"event delegation", look it up for more info!

Missing HTML elements to be hidden or shown

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.

Target HTML generated by Javascript?

I have a slider button created using a JavaScript plugin, which automatically generates an element with class name .flex-next. However, when I run the following code, nothing is logged in my console:
$(window).load(function() {
$( ".flex-next" ).on( "click", function() {
console.log("youclick");
})
});
Since the button is added dynamically after the dom is loaded, you need to use event delegation so the click event can be used on this button:
$(document).on('click','.flex-nex',function() {
console.log("youclick");
})
Your setting your call to fire when the window loads by using $(window).load(...);. A flexsider is initiated on $(document).ready(...) which happens after the window loads and all of the content is loaded into the DOM. So when your script fires, it looks for an element that isnt there yet.
Get around this by firing your script on $(document).ready(), and use event delegation. The best practice way is to declare your function like so:
$(document).ready(
$(document).on('click', ".flex-next", function() {
console.log("youclick");
});
});
this way your click listener will wait until the page is ready and will put a click event on to any .flex-next event, even those created dynamically. That way if your using large imagery that is loaded asynchronously the code will still work.
You are probably calling your $(".flex-next").on call before the slider button has been executed. So, basically, your .flex-next class doesn't exist in the DOM yet when you call the .on
You should call the .on call after plugin has been initialized.

Image does not have width at document.ready

I have a function that I wish to use to resize images:
http://jsfiddle.net/eUurB/
When I run it on document.ready, it has no effect; the image size returned is '0' (You may notice that it does work in the fiddle... I'm not sure what's causing this inconsistencty to be honest, but on my test site it's most definitely returning height and width of '0'.
Is this expected behaviour? If so, how could I make a simple listener for when images have width?
Here's an ultra-safe way to do it that doesn't require waiting for all the images to load, and takes care of situations where the image may be cached or finished loading before the DOM is ready.
$('#my_img').one('load',function(){
resizeImgByArea('logo', 50);
})
.filter(function(){
return this.complete;
})
.load();
.one('load',...) removes the handler as soon as it is invoked. You only need it once.
.filter() will return the image if it was already loaded. If not, it returns no elements.
.load() will manually invoke the handler. This will only occur if the image was already loaded.
So if the image was preloaded before the DOM was ready, we'll invoke its .load() handler manually. If not, its handler will be invoked when it is loaded.
From the jQuery docs on the jQuery(callback) method:
This function behaves just like $(document).ready()
And when we go to the docs on $(document).ready(), we find this:
Description: Specify a function to execute when the DOM is fully loaded.
So it's actually doing what it's supposed to. It isn't waiting for other resources (such as images) to load; it's executing your callback as soon as the DOM is ready.
You could get that <img> element and attach a load event listener, but what if the image really did finish loading, before you could attach it? Your callback will never be executed.
It's not pretty, but I think the safest thing you can do is just wait for the entire page to finish loading:
$(window).load(function () {
resizeImgByArea('logo', 50);
});
Images are not loaded at document.ready time. Instead use the .load() method of jQuery.
$('#logo').load( function() {
resizeImgByArea('logo', 500);
});

Using .live() for iFrame.load() event?

I know an iFrame is added to my page via javascript somewhere in my page, I want to be notified when it is loaded, but this doesn't work:
$("iframe").live("load",
function () {
alert(this.name + ": Im loaded!");
});
No alert is shown
Any idea why? any idea how can we achieve this?
I think you can do a callback after adding the iframe to your page.
As mentioned here, it's not possible to bind live() to iframe load().
Note: The .live() and .delegate() methods cannot be used to detect the
load event of an iframe. The load event does not correctly bubble up
the parent document and the event.target isn't set by Firefox, IE9 or
Chrome, which is required to do event delegation.
So in your callback, you have to call this, maybe set a timeout to make sure it fires after the iframe has been loaded.
$("iframe").load(function () {
alert(this.name + ": Im loaded!");
});
It won't work, for load event only works on Window object.
If you wish to be noticed when page inside the iframe is loaded, then you should write code on the inside page, which calls window.parent to notify its parent page.

Categories

Resources