I am using JavaScript and jQuery to write my website but I get the following problem.
I want to sleep the thread and display a loading animation only until the promise object is completely loaded into my website.
And I don't know how to do that, Can anyone help?
#A.Wolff
Since I have this problem when I am using the PDF.JS plugin. And I am trying to declare a self-defined class on top of it.
Following is my self-defined class
function WhiteBoardPdf3(canvasContext,url){
this.canvasContext=canvasContext;
this.url=url;
this.pdfOriPromise=PDFJS.getDocument(url);
this.pdfPromise=Promise.cast(this.pdfOriPromise);
this.pdfDoc=null;
/*----Here is the problem------*/
this.pdfPromise.then(function getPdf(_pdfDoc){
this.pdfDoc=_pdfDoc
});
/*----------------------------*/
this.pageNum=1;
this.scale=1;
this.renderPage(1);
}
WhiteBoardPdf3.prototype.getPdfPromise=function(){
return this.pdfPromise;
}
WhiteBoardPdf3.prototype.renderPage=function(){
var num=this.pageNum;
var scale=this.scale;
var canvasContext=this.canvasContext;
var canvas=canvasContext.canvas;
var canvasClassName=canvas.className;
var allCanvas=document.getElementsByClassName(canvasClassName);
var canvasContainer=document.getElementById("whiteBoardLayerContainer");
this.pdfPromise.then(function getPdf(_pdfDoc){
_pdfDoc.getPage(num).then(function(page){
var viewport=page.getViewport(scale);
for(var i=0;i<allCanvas.length;i++){
allCanvas[i].height=viewport.height;
allCanvas[i].width=viewport.width;
}
canvasContainer.style.width=viewport.width+'px';
var renderContext={
canvasContext: canvasContext,
viewport: viewport
}
page.render(renderContext);
});
});
}
WhiteBoardPdf3.prototype.getPdfNumOfPages=function(){
this.pdfDoc.numPages;
}
And the PDFJS.getDocument(url) will return a promise object.
However, the problem is that when I construct this class and call the getPdfNumOfPages() function in the main program. I notice that the program will call the getPdfNumOfPages() function before the "pdfDoc"(promise object) is finish loading. So I want to sleep the thread and display the loading animation before the promise object is finish loading. So as to the getPdfNumOfPages() function will run after the "pdfDoc" is loaded.
well you could show a image of loading on your page before sending a ajax request and hide it after a response is received .
HTML CODE:
<img name="loadingImage" id="loadingImg" src="http://www.ppimusic.ie/images/loading_anim.gif " width="100px" height="100px" />
$('#loadingImg').hide();
$.ajax({
url: "test.html",
data: {data1:'smile'},
beforeSend:function() {
$('#loadingImg').show();
},
success:function(response) {
$('#loadingImg').hide();
//process the successful response
},
error:function(response) {
$('#loadingImg').hide();
//process the error response
}
});
Happy Coding:)
Edit:
As indicated in comments (thanks A. Wolff and Frédéric Hamidi), this solution is better:
//
// launch loader
// before
//
// make xhr query
var jqxhr = $.ajax({
url: 'your/action'
});
// call the always promise method, automatically invoked
// when the $.ajax action is completed
jqxhr.always(function() {
// stop loader in every situations (success or failure)
});
Previous solving post solution below:
This solution is enought only if the xhr query is done without error.
You can use $.when
Description: Provides a way to execute callback functions based on one
or more objects, usually Deferred objects that represent asynchronous
events.
//
// set loader on here
//
$.when($.ajax('/action/to/do')).then(function(response) {
// reset your loader
// action completed ;)
});
Related
This might be a stupid question, but I am asking anyways, I have a question about waiting for callbacks.
I am using Polymer in my web development project. In one of my pages, I have a loop that loads an element inside a loop:
loop
"element-a"
end loop
I am fetching data from the database and content of "element-a" is populated from the database query results.
I only want to load another "element-a" once "element-a" has finished loading.
Right now, I have a forced delay by using :
sleepStupidly(usec);
function sleepStupidly(usec)
{
var endtime= new Date().getTime() + usec;
while (new Date().getTime() < endtime);
}
But I need a better way of doing this, any suggestion will be helpful.
As sheriffderek pointed out in the comments, promises or jQuery's $.ajax().success() method are probably the best tools to get this done. In addition, good ol' recursion could be used as well. Below is an example of how to use these within a Polymer (v1) component for your case.
<dom-module id="example-component">
<template></template>
<script>
Polymer({
is:"example-component",
properties: {
//...
},
fetchIndex: 0,
idsToFetch: [1, 2, 3, 4],
elementData: [],
ready: function () {
this.loadElement(this.idsToFetch[this.fetchIndex]);
},
loadElement: function(idToFetch) {
var self = this; // Create a reference for the ".done()" method to use when it fires
$.ajax({
url: "http://example.com/getdata",
data: {"idToFetch": idToFetch}
}).done(function (data) { // This will fire after the response is received, which is where you call the next
self.elementData.push(data); // Save the response data
self.fetchIndex++; // Move to the next element
if (self.fetchIndex < self.idsToFetch.length) { // If there's more to fetch
self.loadElement(self.idsToFetch[self.fetchIndex]); // Recursively call the same method
}
}).always(function(data){ // Optional
console.log("Fetch complete for ID: " + idToFetch);
}).error(function (error){ // Optional
console.log(error)
});
}
})
</script>
</dom-module>
In summary, call the loadElement() method on Polymer's ready() handler and provide it the first element to initiate the fetch. Within loadElement(), make the fetch to get the data for the element ID passed in. Once the fetch is .done() (preferred over but, similar to .success()), recursively call the loadElement() method again and provide it the next element in the list. This will continue recursively until the fetchIndex value equals the length of the idsToFetch array.
You'll have to forgive me if I show any kind of ineptitude here, jquery and java isn't my usual area of work. But here goes:
I have a page that shows a random list of items that are pulled from a server using an API call. The idea is that every time the user clicks "generate" a new list is produced and inserted into the page. This works but it's very fast and all the user sees is a list rapidly changing. To spruce things up I've decided to put some nice animations and effects in.
I've got a jquery function that loops through each element in the list of child elements and toggles the css style of the child element so that an effect from the animate.css library is applied. The problem is when I have another function that loads the new list and this is called immediately and therefore all of the css transitions are ignored; or rather they don't get a chance to run because the second method immediately triggers.
I've tried using a callback and had no joy, I've tried using deferred objects. No luck at all.
Here's the code I have so far:
function removeOldContent() {
$('#removableContent > div').each(function (index) {
var elm = $(this);
setTimeout(function () {
elm.toggleClass('customAnim', function () {
$(this).remove();
});
}, index * 150);
});
}
function getList() {
var rId = $('.tab-content').find('.active').data('d-id');
var serviceUrl = '/GetRandom/GetList';
$.ajax({
type: 'POST',
url: serviceUrl,
data: {
reportId : rId
},
success: function(data) {
$('#reportContainer').html(data).fadeIn('slow');
}
});
}
Ideally I'd like to be able to let removeOldContent() finish completely, after all the timeouts have run. And then trigger getList() to update the content. I'll work on making a nice transition for the inbound data but first I just need to get this working.
Any advice or pointers would be greatly appreciated.
***** Update ******
I've made a fiddle. Not giving me the same error as my dev env but should be close enough for you to see
https://jsfiddle.net/rdt1pfhk/9/
Your problem is with the timing of events. Your removeOldContent function uses a setTimeout function which in turn animates and removes the items from the DOM. Your getList() function was executing before the other function had finished. I put a quick untidy solution together using your fiddle. I return a jquery deferred object from you removeOldContent method and then only call the getList when that is resolved (and the older items removed from the dom). It is not the neatest but it will point you in the right direction. I updated your fiddle here: https://jsfiddle.net/rdt1pfhk/16/
function removeOldContent() {
var deferred = new jQuery.Deferred();
....
return deferred;
}
$(document).on('click', '.quickPick', function (e) {
removeOldContent().then(function(){
getList();
});
});
If I understood correctly you need to only delay some functions for as long as you need. I think the answer you are looking for could be found here:
How to delay calling of javascript function?
Also, I'd like to mention that I don't see a
$(document).ready(function () {
//your code here
});
anywhere. Maybe I'm wrong but since you mentioned that CSS is ignored, are you sure the page is loaded before your code starts being executed?
I'm trying to use jQuery Promises to solve a problem.
I have a UI in which I make an API call and waiting for a response (Which takes a while). I want to wait for the response to see if everything is loaded then do an action. How can I achieve this?
This is my code:
var d1 = new $.Deferred();
if(($('.fa-spin').length + $('.chart-loading').length )==0){
d1.resolve();
} //Logic behind here is, I'm checking for loading icon,
loading spinner and once they are destroyed,
I want to execute something!
$.when(d1).then(function() {
console.log("fetched");
//Run something
});
I want to check if my loading spinner is done, and then fire an event. How can I do this?
When I execute this code, the deferred never gets resolved and fetch is never printed
you'll need to continually check in order to resolve:
var d1 = new $.Deferred();
var testInterval = setInterval(function() {
if(($('.fa-spin').length + $('.chart-loading').length )==0){
clearInterval(testInterval);
d1.resolve();
}
},100);
$.when(d1).then(function() {
console.log("fetched");
//Run something
});
this will check every .1sec if the spinner's gone, and resolve your defer object when the condition is met. although, you could just run your code there instead of as a defer/resolve.
additionally it might be more effective to hook into your actual process rather than the existence of a spinner dom object, consider implementing an existing observer pattern or roll your own: observer pattern
I'm using the video.js plugin. I'm using ajax to load in another bunch of videos from another page but I want to call the javascript again to perform the skinning again. Is there a callback function I can use after my ajax has finished loading in the html?
To be specific I'm after the actual function name (if there is one) that video.js has made. ie the javascript which runs to dress up the videos.
Ajax has a success call back you may be able to use.
$.ajax({
type: "GET",
url: url,
success: function(data){
//Call back stuff
}
});
There are also, error and other callbacks you can use. You can find information on here.
If you don't have access to the ajax event, you can still bind to the success call back. Here's documentation on how to do it.
The best solution I found was here
(function(){
var video = document.querySelector('video');
var onDurationChange = function(){
if(video.readyState){
//to your thing
}
};
video.addEventListener('durationchange', onDurationChange);
onDurationChange();
})();
Trying to do
videojs("myplayer").ready(function() {
console.log(this.duration()); //0
});
wouldn't work.
let's say I'm doing 3 ajax calls and I want to wait for the 3 calls to finish before doing something.
Is there a library out there to synchronize multiple async events in JavaScript ? (using or not jQuery's event system)
Ex.:
var sync = new syncLib();
$('a1').click(sync.newListener());
$('a2').click(sync.newListener());
sync.wait(function(e1, e2) {
// fired when both a1 and a2 are clicked or when 10 seconds have passed
// e1 and e2 would have properties to know whether or not they timed out or not..
}, 10 /* timeout */));
I have found this one: https://github.com/Ovea/js-sync/blob/master/README.md, but timeouts are not supported. (Let's say the second ajax call takes too long, I don't want my synchronization to be hung up, I want to set a 10 secs timeout)
I know I can code something myself, but I'm just checking here (after googling for it)
Thanks!
EDIT:
Since then I found async: https://github.com/caolan/async
$.when($.ajax("/"), $.ajax("/"), $.ajax("/")).then(function () {
alert("all 3 requests complete");
});
Documentation
you can use jquery deferred object
here is a useful post http://www.erichynds.com/jquery/using-deferreds-in-jquery/
The .deferred, .when, .then solution mentioned in other answers is much more elegant, but it's also possible write your own simple solution just so you see how this can be done manually. You just set a counter for how many ajax calls you have in flight and in the success handler for each ajax calls, you decrement the counter and fire your action when the counter gets to zero.
function DoMyAjaxCalls(callbackWhenDone) {
var numAjaxCalls = 3;
// set timeout so we don't wait more than 10 seconds to fire the callback
// even if ajax calls aren't done yet
var timer = setTimeout(callbackWhenDone, 10*1000);
function checkAjaxDone() {
--numAjaxCalls;
if (numAjaxCalls == 0) {
clearTimeout(timer);
callbackWhenDone();
}
}
// first ajax call
$.ajax({
url: 'ajax/test1.html',
success: function(data) {
// write code to handle the success function
checkAjaxDone();
},
error: checkAjaxDone
});
// second ajax call
$.ajax({
url: 'ajax/test2.html',
success: function(data) {
// write code to handle the success function
checkAjaxDone();
},
error: checkAjaxDone
});
// third ajax call
$.ajax({
url: 'ajax/test3.html',
success: function(data) {
// write code to handle the success function
checkAjaxDone();
},
error: checkAjaxDone
});
}
Here you have a [library][1] based on jQuery made for that purpose.
In simple use-cases, $.when() is BEST but jcon-q-rency allows you to synchronize any asynchronous code sections.
http://www.megiddo.ch/jcon-q-rency