After updating the DOM with a new element (e.i. body.append(html)), I cannot immediately get the height of the newly updated element (e.g. body.height()). A partial fix is setting a time interval and getting the height at the end of time interval (setTimeout("alert(body.height)", 500)).
Any better ideas? Like a callback after DOM completely updates? Thanks.
Edit:
This only happens when there is a lot going on in the background (i.e. when page first loads). It would seem like the page update is almost instantaneous if nothing else is being processed. What I need is a callback, or an indicator of when the DOM is reformed!
Edit:
The problem is from the browser being 'distracted' by other processes, which makes the browser unable to update immediately after the append of the element. How do I fix this?
The timeout method works because the rendering engine is given a chance to display the new element there by giving it a change to render it and thus assigning it a height.
You can set the timeout to 0 and still have the same effect.
With jQuery works fine for me.
In the jsfiddle demo I put the next code:
$(function(){
var jTest = $('#test');
console.log('The height:',jTest.innerHeight(),jTest.height()); //Show me 'The height: 20 20'
jTest.append('<div><br/>How are you?</div>');
console.log('The height:',jTest.innerHeight(),jTest.height()); //Show me 'The height: 60 60'
});
Unless you mean javascript only solution or put a jsFiddle demo to show your error.
Related
There is a single Page Application in AngularJS.
It has nested tabs. In the inner tab there is a button on which some event gets fired.I need to trigger the click event of this button present on the inner tab Button gets rendered after both the tabs are rendered. What is the best way to wait until the tabs render themselves and the button is available.
I tried using 'while loop'(i.e keep looping until id for button is undefined) and $timeout(set timeout to 2-3 seconds) service but both have their consequences when there is delay in tab render.
Please suggest if there exists a better approach.
Even though this question is really old, I've found a solution that works for me and I think it might be helpful for some people.
Calling element.getBoundingClientRect() before executing further code worked for me. According to docs this method returns information about the position relative to the viewport (docs):
The Element.getBoundingClientRect() method returns a DOMRect object providing information about the size of an element and its position relative to the viewport.
Assuming that the screen has to render to find information about the position of an element, this function would technically wait for the html element to render or even make the html element render.
Remember, this is only an assumation and I can't guarantee that it works.
Things have changed quite a bit since this question was asked, so there's now a much nicer solution.
requestAnimationFrame(() => {
// this will be called just before the next video frame.
// That will be after any changes to the DOM have been completed.
});
The docs are here...
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
You can do it with jQuery:
$(document).ready(callbackFn);
or native JS:
document.addEventListener('readystatechange', function onReadyStateChange() {
if (document.readyState !== "complete")
return;
callbackFn();
}, false);
I need to add an HTML5 video to a page with the following code:
document.querySelector("#mydiv").appendChild(video);
console.debug(document.querySelector("video").clientWidth);
My problem is, the second line returns 0 because it takes a while for the video tag to load the video it's going to play. If I manually type the second line in the console once the page is loaded, I get the actual value. Is there a better way to get this value than using timeouts to periodically check if the value's been updated?
I needed to do something similar and stumbled upon this question, as I though maybe there is a callback for this. Turns out there is not. So here is another way of doing it using Window.requestAnimationFrame().
It would look something like this:
// Prepare the new element
let video = document.createElement('video');
// Add the element to the DOM. Works with any element
document.querySelector("#mydiv").appendChild(video);
// Updateing the DOM will cause a re-render, which we can hook into
window.requestAnimationFrame(() => {
console.debug(document.querySelector("video").clientWidth);
});
<div id="mydiv">Video goes here:</div>
Check the console to see that it works.
Javascript is one-threaded.
You should to drop your code to event-loop, this allows the js with DOM work.
Just try followed:
document.querySelector("#mydiv").appendChild(video);
setTimeout(function(){
console.debug(document.querySelector("video").clientWidth);
});
Add a video.onloadstart event to the element.
video.onloadstart(getClientWidth);
document.querySelector("#mydiv").appendChild(video);
function getClientWidth() {
console.debug(document.querySelector("video").clientWidth);
}
Read more here.
I have a photo gallery powered by Isotope.Images are requested from external resource on page load and every time a user scrolls to the bottom of the page. New images are to be appended to the current isotope layout. The problem is with Isotope - it doesn't seem to execute the 'appended' method.
Searching for a solution on StackExchange and Google revealed I am not the only one having this problem. I have been tinkering with this for past couple of days and tried almost every solution I could find but so far I have not found anything that could fix my problem.
CodePen: I have created a CodePen here - http://codepen.io/Writech/pen/pBoEt
WebPage: As the custom event 'resizestop' is not working in codepen the same code is found as a webpage here - http://writech.net.ee/sandbox/
To see the problem open the CodePen or WebPage provided above and scroll to the bottom of the page which initiates loading of additional images. Then you see the new images are just appended to the container by jQuery. But they are not appended to the isotope layout instance as they are supposed to.
The problematic part lays in a custom function named isotopeAppend(). This function is called on page load and then the second part of 'if-else' statement is executed. When initialization is done and first images are added to the container then the next time isotopeAppend() is called (it's when user reaches to the bottom of the page) the first part of 'if-else' statement is executed and this is where the problematic Isotope 'appended' method is called.
A code snippet below from problematic javascript code. The results of the ajax request to external resource are applied to the variable newElems. When adding an alert('something') or console.log inside the 'appended' callback - nothing happens.
Does the problem lay in Isotope itself or does it have anything to do with my coding error?
I would really like to find a solution for this!
var elements = $(newElems).css({ opacity: 1, 'width' : columnWidthVar + 'px' });
$('#photos_section_container').append( elements );
$('#photos_section_container').imagesLoaded(function(){
$('#photos_section_container').isotope( 'appended', elements, function(){
hideLoader(function(){
elements.animate({ opacity: 1 });
});
});
});
In the initialization change
itemSelector : $('.photos_section_wrap'),
to
itemSelector : '.photos_section_wrap',
I forked your pen.
itemSelector is used by isotope to filter elements to layout and $() returns array of objects. In result there no elements to layout. If you are interested you may look at the _getAtoms method (isotope script) in debug to see what's goinig on.
I have div with vertical scroll bar. Div is being updated dynamically via ajax and html is inserted using jQuery's .html method.
After div is updated scroll bar returns to top and I am trying to keep it in the previous position.
This is how I'm trying it:
var scrollPos = $('div#some_id').scrollTop(); //remember scroll pos
$.ajax({...
success: function(data) {
$('div#some_id').html(data.html_content); //insert html content
$('div#some_id').scrollTop(scrollPos); //restore scroll pos
}
});
This fails. My best guess is that it is failing due to inserted html not rendered (ie. no scroll).
For example this works.
setTimeout(function(){
$('div#some_id').scrollTop(scrollPos);
}, 200);
But this is dirty hack in my opinion. I have no way of knowing that some browsers won't take more then these 200ms to render inserted content.
Is there a way to wait for browser to finish rendering inserted html before continuing ?
It's still a hack, and there really is no callback available for when the HTML is actually inserted and ready, but you could check if the elements in html_content is inserted every 200ms to make sure they really are ready etc.
Check the last element in the HTML from the ajax call:
var timer = setInterval(function(){
if ($("#lastElementFromAjaxID").length) {
$('div#some_id').scrollTop(scrollPos);
clearInterval(timer);
}
}, 200);
For a more advanced option you could probably do something like this without the interval, and bind it to DOMnodeInserted, and check if the last element is inserted.
I will just like to point out one difference here: One thing, is when the .html() have completed loading, but the browser actually render the content is something different. If the loaded content is somewhat complex, like tables, divs, css styling, images, etc - the rendering will complete somewhat later than all the dom ellements are present on the page. To check if everything is there, does not mean the rendering is complete. I have been looking for an answer to this by myself, as now I use the setTimeout function.
Such callback does not exists because .html() always works synchronously
If you are waiting for images loading, there's one approach https://github.com/desandro/imagesloaded
I used Easy Slider jQuery plugin before and never had problem until now. And the problem is strange. Check out this home page
http://bit.ly/HKiWY6
The page will pop an alert showing two values:
$("#slider").width()
and
$("#slider3").width()
I already set the value for both in css. One is 710px and one is 700px.
If you run in IE9, it shows the default value of $(window).width() instead for both, whatever the window or document width currently is. FF and Chrome returned correctly. Why is that?
Try the outerWidth, and make sure to wrap it in a windows.ready event listener to make sure all DOM element rendered properly before the width being computed
$("#slider3").outerWidth()
I've had problems with jQuery's width()/height()/offset().top/.left etc in the past when I used them before a certain event fully bubbled. See if setTimeout(function() { alert($('#slider').width()); }, 0); has any effect. It's a cheap nextTick() trick that might be just what you need.