I'm doing some basic ajax requests for changing pages, example:
$(document.body).on('click', ".paging a", function (e) {
$.ajax({
type: "GET",
url: $this.attr('href'),
success: function (data) {
$("#main-content").html(data);
}
});
e.preventDefault();
return true;
});
The URL the ajax request calls to returns HTML, sometimes this HTML contains 30-40 <img> images.
The problem I'm hitting is if you click two pages in quick succession there is a delay while the browser waits until it has loaded all the images in the HTML of the previous ajax request until it makes the next XHR call.
Is there a way to prioritise the XHR request ahead of the images? Basically if another page is clicked I want all current requests to stop and the XHR request to execute immediately. As far as I've seen this is occurring because browsers have a limit to how many asynchronous requests it'll make to one domain (i.e. 6 for chrome) and if I changed the images to use a sub-domain it would probably fix it, but I'm trying to find a way to do it without having to resort to sub-domains.
Using XMLHttpRequest you can load images and abort.
var xhrAr = Array();
function abortXhr(){
for(var key in xhrAr)
xhrAr[key].abort();
xhrAr = Array();
}
function startXhr(dataObj){
var imgObj = dataObj.find('img');
imgObj.each(function(){
var thisObj = $(this);
var src = $(this).attr('src');
$(this).attr('src', ''); //prevent loading
var xhr = new XMLHttpRequest();
xhr.open("GET", src, true);
xhr.responseType = "blob";
xhr.onload = function(){
var imageUrl = (window.URL || window.webkitURL).createObjectURL(this.response);//Creating blob ul
thisObj.attr('src', imageUrl);
}
xhr.send();
xhrAr.push(xhr);
});
}
$(document.body).on('click', ".paging a", function (e) {
abortXhr(); //abort
$.ajax({
type: "GET",
url: $this.attr('href'),
success: function (data) {
var dataObj = $(data);
startXhr(dataObj);//Start
$("#main-content").append(dataObj);
}
});
e.preventDefault();
return true;
});
When the user clicks on a new page, you could
Store the html of "#main-content" element in a variable
Empty the all src attributes of tags in "#main-content"
Make your XHR request
Reset the settings of "#main-content"
This way the img http connections are aborted, the XHR request is fired and finally your image requests resume from where they were left. (this can vary on the cache settings for your images)
$('#goto-page-2').click(function (e) {
var mainContentHTML = $("#main-content").html();
$("#main-content").find('img').attr('src', ''); //clear images
$.ajax({
type: "GET",
url: $this.attr('href'),
success: function (data) {
}
});
$("#main-content").html(mainContentHTML); // reset images
e.preventDefault();
return true;
});
References
How to cancel an image from loading
In this case you are changing your page content and that content is having images so images is taking time. so in this case you can do one thing if you know which image you are using on those page then load them all images on main page when first time your page is loading.you can have these all image in a hidden div. and when your page content is changes that have these images then it will start showing very quickly becuase they are already in browser memory.
Related
I have an ajax call returning html code which is inserted into a container.
Now I need to call a jQuery function to format the gallery, but I can't find a way to ensure that the jQuery function waits for returnedData to be fully loaded/rendered.
As you can see I have tried .ready() but it doesn't work. I have also tried setTimeout, which actually works, but as the returnedData can contain a lot of images, I can't use it as I don't know how long it would take to load all the images.
Any ideas?
$(document).ready(function() {
$.ajax(url, {type: 'POST', dataType: 'json', data: data, success: success_handler});
});
function success_handler(returnedData) {
$('.category-images-js').html(returnedData);
$('.category-images-js').ready(function() {
// Code to run after all data inside returnedData is fully ready/rendered
);
}
SOLUTION:
This thread: How to know if all elements in a DIV have been fully loaded? worked for me but I had to make a work-around as the code I run, when data inside returnedData is fully ready/rendered, makes the on load trigger 3 times per image.
I've made my own ajax function so i hope it fits you:
function xhr(u, c) {
var x = new XMLHttpRequest();
x.onreadystatechange = function (){
if (x.readyState == 4 && x.status == 200){
c(x.responseText)
}
};
x.open("GET", u, true);
x.send()
}
u = URL
c = Callback function
I am loading a page through xmlHttpRequest and I am not getting one variable which come into existance after some miliseconds when page loading is done
so the problem is when xmlHttpRequest sends back the response I do not get that variable in it.
I want it to respond back even after onload.
var xhr = new XMLHttpRequest();
xhr.open("GET", event.url, true);
xhr.onload = function() {
callback(xhr.responseText);
};
xhr.onerror = function() { callback(); };
xhr.followRedirects = true;
xhr.send();
I tried setTimeOut but of no use because may be at that time call is finished
xhr.onload = function() {
console.log('wait for response');
setTimeout(function(){
callback(xhr.responseText);
},2000);
};
I tried readyStateChange , but no success
xhr.onreadystatechange = function () {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
console.log(xhr.responseText);
callback(xhr.responseText);
};
};
by the way, I am trying to load amazon signIn page
and the variable which is missing everytime is hidden Input Field metadata1,
I get all other hidden Input fields in response text , except input field, named "metadat1"
I'll be more than Happy, If anyone can help.
Thanks in advance
ohh Finally I did it,
I din't read any javascript, Instead I just extracted scripts which I received in xhr calls and executed it inside a hidden div, and here it is , I got that variable's value
abc(xhr.responseText);
function abc(xhrRes){
var dynamicElement = document.createElement('div');
dynamicElement.setAttribute("id", "xhrdiv");
dynamicElement.setAttribute("style", "display: none;");
dynamicElement.innerHTML = xhrRes;
document.body.appendChild(dynamicElement);
var scr = document.getElementById('xhrdiv').getElementsByTagName("script");
//5 scripts needed to generate the variable
for(i=0;i<5;i++){
eval(scr[i].innerHTML);
if( i+1 == 5){
var response = document.getElementById('xhrdiv').innerHTML;
return response; //and in this response variable I have every thing I needed from that page which I called through xmlhttp Req
}
}
}
---------------------Improved Version-----------------------
Instead of executing script through eval,
keep script content in a file AND Include it, as we normally include the script, that works better.
xhrRes = xhr.responseText;
var dynamicElement = document.createElement('div');
dynamicElement.setAttribute("id", "xhrDiv");
dynamicElement.setAttribute("style", "display: none;");
dynamicElement.innerHTML = xhrRes;
document.body.appendChild(dynamicElement);
var xhrDiv = document.getElementById('xhrDiv');
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.src = JSfile;
xhrDiv.appendChild(newScript);
(it shows the edit is done my anonymous user, :( because I forgot to Login, while editing)
If the data doesn't exist until some time after the page has loaded then, presumably, it is being generated by JavaScript.
If you request the URL with XMLHttpRequest then you will get the source code of that page in the response. You will not get the generated DOM after it has been manipulated by JavaScript.
You need to read the JavaScript on the page you are requesting, work out how it is generating the data you want to read, and then replicate what it does with your own code.
I would like to seek your help about xmlhttprequest. I would like to perform xmlhttp request sending out to get pictures repeatly from server only when the previous http response is received.
In server side, I have created http responses which tagged with xmlhttp status =900.So I want to send out the request once the response due to previous request is received, otherwise, the program should wait until its arrival.
For example:
When I press the button somewhere in the browser, it triggers first picture (jpeg) request to server, then waiting the server's response. After getting the Http response with status marked as 900, xmlhttp will decode the response and display the picture on (image).
In the following code, by capturing the packet with wireshark, I think I success to get the right packet flow. However, the picture can not be shown in the DIV.
Can anyone help me ? Thanks a lot and a lot!
enter code here
function init(url)
{
var xmlHTTP = new XMLHttpRequest();
xmlHTTP.open('GET',url,true);
xmlHTTP.send();
xmlHTTP.responseType = 'arraybuffer';
xmlHTTP.onload = function(e)
{
var arr = new Uint8Array(this.response);
var raw = String.fromCharCode.apply(null,arr);
var b64=btoa(raw);
var dataURL="data:image/jpeg;base64,"+b64;
document.getElementById("image").src = dataURL;
};
xmlHTTP.onreadystatechange=function(){
buff(xmlHTTP.status);
}
}
buff(status){
if (status=900){
sleep(1000);
init('/images/photos/badger.jpg');
}
}
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
</script>
</head>
<body>
<div id="image"><h2>picture display here</h2></div>
<button type="button" onclick=buff(900)>Get Picture</button>
enter code here
There are several problems with your code.
Markup
The problem with your markup is, that you are using a div tag to display an image. The src attribute is not supported on div tags. You should use an img tag instead like this:
....
<img id="image" />
<button type="button" onclick="buff(900)">Get Picture</button>
Statuscode
Why are you using a status of 900? If the request was correct and the image was loaded, please use a status of 200.
Image loading
Why are you even using an XMLHttpRequest for loading images?
You could simply change the src attribute on the img tag and the browser will request the image.
If you want to reload the image you could just refresh the src attribute. If all images a served under the same URL, you can add a request param like the current time:
document.getElementById("image").src = "/images/photos/badger.jpg#" + new Date().getTime();
This way the browser will request the image again and won't use the one allready loaded and cached. See this answer for further info. (Actually the question is nearly the same as yours...)
Sleep function
Your sleep function will use resources because it's a loop that will constantly run for the specified time. While it runs, it will add numbers and do comparisons that are completly unnecessary.
please use something like the javascript build in setTimeout():
buff(status) {
if(status === 900) {
setTimeout(funciton(){
init('/images/photos/badger.jpg');
}, 1000);
}
}
Update: working example
I set up a working example in the code snippet. It loads images from the same url, but they are served randomly on each request by lorempixel.
I reorganized the image loading. Actually there was another problem. You startet the next image loading with onreadystatechange. This will fire for each change of the readystate and not only when the image is loaded. Therefore I start the next buff() from the onload() like so:
var xmlHTTP = new XMLHttpRequest();
xmlHTTP.open('GET',url,true);
xmlHTTP.responseType = 'arraybuffer';
xmlHTTP.onload = function(e) {
var arr = new Uint8Array(this.response);
var raw = String.fromCharCode.apply(null,arr);
var b64 = btoa(raw);
var dataURL = "data:image/jpeg;base64," + b64;
document.getElementById("image").src = dataURL;
buff(this.status);
};
xmlHTTP.send();
For convenience I added a button for stopping the loading of new images.
For your example you just have to change the imageUrl and imageStatus variables.
var imageUrl = "http://lorempixel.com/400/200/", // set to "/images/photos/badger.jpg" for your example
imageStatus = 200, // set to 900 for your example
stopped = true;
function stopLoading() {
stopped = true;
}
function loadNextImage(url) {
if(!stopped) { // only load images if loading was not stopped
var xmlHTTP = new XMLHttpRequest();
xmlHTTP.open('GET',url,true);
xmlHTTP.responseType = 'arraybuffer';
xmlHTTP.onload = function(e) {
var arr = new Uint8Array(this.response);
var raw = String.fromCharCode.apply(null,arr);
var b64 = btoa(raw);
var dataURL = "data:image/jpeg;base64," + b64;
document.getElementById("image").src = dataURL;
buff(this.status); // set the next timer when the current image was loaded.
};
xmlHTTP.send();
}
}
function buff(status) {
if (status === imageStatus) {
setTimeout(function() {
loadNextImage(imageUrl + "?" + new Date().getTime());
}, 1000);
} else {
// Status does not match with expected status.
// Therefore stop loading of further images
stopLoading();
}
}
function init() {
stopped = false;
loadNextImage(imageUrl);
}
document.getElementById("start").onclick = function(){
init(imageUrl);
};
document.getElementById("stop").onclick = stopLoading;
<img id="image" />
<button type="button" id="start">Get pictures</button>
<button type="button" id="stop">No more pictures</button>
I am new to working with AJAX and have some experience with Java/Jquery. I have been looking around for an solution to my problem but i cant seem to find any.
I am trying to build a function in a webshop where the product will appear in a popup window instead of loading a new page.
I got it working by using this code:
$(".product-slot a").live('click', function() {
var myUrl = $(this).attr("href") + " #product-content";
$("#product-overlay-inner").load(myUrl, function() {
});
$("#product-overlay").fadeIn();
return false;
});
product-slot a = Link to the product in the category page.
product-content = the div i want to insert in the popup from the product page.
product-overlay-inner = The popup window.
product-overlay = The popup wrapper.
The problem that i now have is that my Javascript/Jquery isnt working in the productpopup. For example the lightbox for the product image or the button to add product to shoppingcart doesnt work. Is there anyway to make the javascript work inside the loaded content or to load javascript into the popup?
I hope you can understand what my problem is!
Thank you in advance!
EDIT: The platform im using has jquery-ui-1.7.2
I know this is an old thread but I've been working on a similar process with the same script loading problem and thought I'd share my version as another option.
I have a basic route handler for when a user clicks an anchor/button etc that I use to swap out the main content area of the site, in this example it's the ".page" class.
I then use a function to make an ajax call to get the html content as a partial, at the moment they are php files and they do some preliminary rendering server side to build the html but this isn't necessary.
The callback handles placing the new html and as I know what script I need I just append it to the bottom in a script tag created on the fly. If I have an error at the server I pass this back as content which may be just a key word that I can use to trigger a custom js method to print something more meaningful to the page.
here's a basic implementation based on the register route handler:
var register = function(){
$(".page").html("");
// use the getText ajax function to get the page content:
getText('partials/register.php', function(content) {
$(".page").html(content);
var script = document.createElement('script');
script.src = "js/register.js";
$(".page").append(script);
});
};
/******************************************
* Ajax helpers
******************************************/
// Issue a Http GET request for the contents of the specified Url.
// when the response arrives successfully, verify it's plain text
// and if so, pass it to the specified callback function
function getText(url, callback) {
var request = new XMLHttpRequest();
request.open("GET", url);
request.onreadystatechange = function() {
// if the request is complete and was successful -
if (request.readyState === 4 && request.status === 200) {
// check the content type:
var type = request.getResponseHeader("Content-Type");
if (type.match(/^text/)) {
callback(request.responseText);
}
}
};
// send it:
request.send(null); // nothing to send on GET requests.
}
I find this a good way to 'module-ize' my code into partial views and separated JavaScript files that can be swapped in/out of the page easily.
I will be working on a way to make this more dynamic and even cache these 'modules' for repeated use in an SPA scenario.
I'm relatively new to web dev so if you can see any problems with this or a safer/better way to do it I'm all ears :)
Yes you can load Javascript from a dynamic page, but not with load() as load strips any Javascript and inserts the raw HTML.
Solution: pull down raw page with a get and reattach any Javascript blocks.
Apologies that this is in Typescript, but you should get the idea (if anything, strongly-typed TypeScript is easier to read than plain Javascript):
_loadIntoPanel(panel: JQuery, url: string, callback?: { (): void; })
{
// Regular expression to match <script>...</script> block
var re = /<script\b[^>]*>([\s\S]*?)<\/script>/gm;
var scripts: string = "";
var match;
// Do an async AJAX get
$.ajax({
url: url,
type: "get",
success: function (data: string, status: string, xhr)
{
while (match = re.exec(data))
{
if (match[1] != "")
{
// TODO: Any extra work here to eliminate existing scripts from being inserted
scripts += match[0];
}
}
// Replace the contents of the panel
//panel.html(data);
// If you only want part of the loaded view (assuming it is not a partial view)
// using something like
panel.html($(data).find('#product-content'));
// Add the scripts - will evaluate immediately - beware of any onload code
panel.append(scripts);
if (callback) { callback(); }
},
error: function (xhr, status, error)
{
alert(error);
}
});
}
Plain JQuery/Javascript version with hooks:
It will go something like:
var _loadFormIntoPanel = function (panel, url, callback) {
var that = this;
var re = /<script\b[^>]*>([\s\S]*?)<\/script>/gm;
var scripts = "";
var match;
$.ajax({
url: url,
type: "get",
success: function (data, status, xhr) {
while(match = re.exec(data)) {
if(match[1] != "") {
// TODO: Any extra work here to eliminate existing scripts from being inserted
scripts += match[0];
}
}
panel.html(data);
panel.append(scripts);
if(callback) {
callback();
}
},
error: function (xhr, status, error) {
alert(error);
}
});
};
$(".product-slot a").live('click', function() {
var myUrl = $(this).attr("href") + " #product-content";
_loadFormIntoPanel($("#product-overlay-inner"), myUrl, function() {
// Now do extra stuff to loaded panel here
});
$("#product-overlay").fadeIn();
return false;
});
Look at this code please - how could I kill / update or restart an ajax call (not content that Ajax calls) after the content has already been called?
I mean the $('#posting_main') is called onclick and animated - how to stop ajax and make it another $('#posting_main') on another click?
$(document).ready(function() {
$("#img_x_ok").click(function(e){
e.preventDefault();
var post_text = $.trim($("#main_text_area").val());
var data_text = 'post_text='+ post_text;
if (post_text === "") return;
var xhr = $.ajax({
type: "POST",
url: "comm_main_post.php",
data: data_text,
cache: false,
success: function (data){
//content
$("#posting_main").fadeIn();
$("#posting_main").load("pull_comm.php");
$("#main_text_area").attr("value", "");
$("#posting_main").animate({
marginTop: "+=130px",
}, 1000 );
}
}); //ajax close
}); }); //both functions close
You can abort the current request with:
xhr.abort();
After having done that, you can run another $.ajax(...) to make a second request.
You could implement it like the following. Note that indenting code makes it a lot more readable!
$(document).ready(function() {
var xhr; // by placing it outside the click handler, you don't create
// a new xhr each time. Rather, you can access the previous xhr
// and overwrite it this way
$("#img_x_ok").click(function(e){
e.preventDefault();
var post_text = $.trim($("#main_text_area").val());
var data_text = 'post_text='+ post_text;
if (post_text === "") return;
if(xhr) xhr.abort(); // abort current xhr if there is one
xhr = $.ajax({
type: "POST",
url: "comm_main_post.php",
data: data_text,
cache: false,
success: function (data){
//content
$("#posting_main").fadeIn();
$("#posting_main").load("pull_comm.php");
$("#main_text_area").attr("value", "");
$("#posting_main").animate({
marginTop: "+=130px",
}, 1000 );
}
});
});
});
I am not sure I fully understand your question, however:
xhr.abort() will kill the AJAX request. After calling abort(), you could modify and resend the request, if desired.
$("#posting_main").stop() will stop the fadeIn animation. (And I think you might need to follow that with $("#posting_main").hide() to be sure it isn't left partially visible.)