Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I have an APEX application with a button that is calling a javascript function. The function is doing some screen scraping and takes a few seconds to complete. I want to display a spinner icon first to provide the sense that something is happening. However, even though I have the spinner displaying with a jquery .show() call prior to the function call, they seem to both get executed at the same time....seconds after the button click. It's as if the jquery .show() won't execute until the function call is complete. How do I get the .show() to execute prior to the call to the function? I even tried adding the .show() to the first line of the function but the result is the same. Spinner doesn't display until after the function has completed.
Show accepts a callback function as a parameter. See example below.
jQuery.show() documentation
function buttonHandler() {
$(".spinner").show(function() {
// this will be executed after show has completed
});
}
How do I get the .show() to execute prior to the call to the function?
You call .show, then yield back to the browser for a tiny bit of time, before calling the function, like this:
function buttonHandler() {
$("...").show();
setTimeout(theFunction, 0);
}
You'll have to experiment with your target browsers to determine whether you need a value larger than 0. The value is in milliseconds, so anything up to 50 or so will be largely-unnoticable to a human.
By not calling the function until after you've yielded back to the browser, you give the browser a chance to update the display.
Note that the spinner may not be animated while the function is tying things up, it depends on the browser. You may prefer to show something static but dynamic-looking (the way "go faster" stripes are) to avoid inconsistency between browsers.
Live example using 50ms:
$("#the-button").on("click", buttonHandler);
function buttonHandler() {
$("#spinner").show();
$("#done").hide();
setTimeout(theFunction, 50);
}
function theFunction() {
var target = Date.now() + 1000;
while (Date.now() < target) {
// Do nothing, we're just simulating a busy function
}
$("#spinner").hide();
$("#done").show();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type="button" id="the-button" value="Click me">
<div id="spinner" style="display:none">We're doing it, one sec!</div>
<div id="done" style="display:none">Function is done now</div>
Related
Trying to automate a task in the browser with Greasemonkey.
Requirement: load a web page which contains a table displaying 15 out of 340+ results, with button controls to see the next page worth of results, go back, go to the end and so forth.
Collect the first 15 results --> got this working
Click on the 'Next' button --> got this working
Wait until the page loads the next set of results --> dont know how
Repeat until the next button is disabled --> got this working
Cant show pictures cuz its a corporate app.
So far if I loop with setTimeouts, the timeouts get queued up and executed at the same time I think. Instead, the requirement is for the code to run the info collection, click next, wait, then collect info again.
You could try a utility function waitForKeyElement, a greasemonkey utility script. It is essentially doing what you were trying to do before. It sets a timeout to continuously checks to see if an element is loaded. Executing it would look something like this:
waitForKeyElements (
"div.comments",
commentCallbackFunction
);
Where comment callback function would be the function that collects results.
It would help also to understand why setTimeout in a loop doesn't work. setTimeout does not block execution of a script to run your callback function. It queues up that function to be executed no earlier than the time that you pass in as a second parameter. Because of this, the loop runs very quickly and instead of getting function calls at 3000ms, 6000ms, and 9000ms... as you might expect you get something closer to function calls at 3000ms, 3001ms, 3002ms.
You can execute arbitrary JS logic mixed with API calls, recursion and timeouts sequentially via synchronous executor nsynjs:
function synchronousCode() {
var i=0;
while(true) {
console.log("waiting 1 sec, iteration", i++);
$('#myDiv').toggle();
nsynWait(nsynjsCtx,1000);
};
}
var ctx;
function btnStopClicked() {
ctx.stop();
ctx=null;
}
function btnStartClicked() {
ctx=nsynjs.run(synchronousCode,{},function(){
console.log("Synchronous Code done");
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>
<script src="https://rawgit.com/amaksr/nsynjs/master/wrappers/nsynWait.js"></script>
<body>
<button id="buttonStart" onclick="btnStartClicked()">Start</button>
<button id="buttonStop" onclick="btnStopClicked()">Stop</button>
<div id="myDiv">Flashing div</div>
</body>
See more examples here: https://github.com/amaksr/nsynjs/tree/master/examples
Thanks people, found this post to be the best answer
Synchronous setTimeout + Loop
This way the page loads, the first values are read, the next button is clicked, next results appear and are read, until the last page.
Thanks again for the input and ideas
you can use it
for(const elment of arrayElements) {
await yourFunc(elment)
await yourOtherFunc('somePatameter')
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am using velocity.js for pulse animation.
I have simple code
In html I have :
XXXXXXXXXXX
In javascript:
var blinkNext = 0; // Global variable
var blinkBtn = function() {
$("div").velocity("callout.pulse");
};
blinkNext = setInterval(blinkBtn, 1);
clearInterval(blinkNext); // <-- Not working
Expected behavior: div section should pulse and then get stopped.
Problem: clearInterval is not stopping pulse callout.
I searched alot but couldn't found anything
You have the interval set to just a single millisecond, so you are calling .velocity() every millisecond, and I assume those calls queue up. So when you clear the interval, it is going to take a very long time for the animation to stop.
Here's a jsfiddle that demonstrates the problem with the original code. Click "Run >" and then click the "stop" button as fast as you can. You can see how many times "blink" is written to the console log. That is how many times the animation will run before it stops, but it will eventually stop.
Instead of using setInterval(), you could do the following:
var blinking = true;
function blink() {
$('#btnNext').velocity('callout.pulse', function() {
// This anonymous function is called when the animation completes.
// If we should be blinking, then we call blink() again.
if (blinking) {
blink();
}
});
}
// Initially start the animation.
blink();
// This button shows how you can stop and restart the animation.
$('#toggleBtn').click(function() {
blinking = !blinking;
if (blinking) {
blink();
}
});
jsfiddle
Background
I've inherited an ancient web application that has input controls with custom behaviors defined with an old-fashioned HTC (HTML Component) script, e.g.:
<input name="txtFiscalYearEndDay" type="text" value="30"
maxlength="2" size="5" id="txtFiscalYearEndDay" class="Text1"
style="behavior:url(/path/js/InFocus.htc);" />
Here are the relevant parts of this HTC file to illustrate the issue:
<PUBLIC:COMPONENT tagName="InFocus">
<PUBLIC:METHOD NAME="setValid" />
<PUBLIC:ATTACH EVENT="ondocumentready" HANDLER="initialize" />
<SCRIPT LANGUAGE="javascript">
function initialize() {
// attaches events and adds CSS classes, nothing fancy
}
function setValid(bInternal) {
// checks some flags and changes a label
}
</SCRIPT>
</PUBLIC:COMPONENT>
So, nothing out of the ordinary so far. Additionally, I have some JS that runs on DOM-ready:
$(function() {
txtFiscalYearEndDay_Validate(document.getElementById('txtFiscalYearEndDay'));
});
And the validation function:
function txtFiscalYearEndDay_Validate(el) {
...
}
Note: I'm not using $('#txtFiscalYearEndDay') because then I really can't try to call setValid(true); on the element, nor do I want to have to do $('#txtFiscalYearEndDay')[0].setValid(true);.
The problem
At one point in the validation function, I'm attempting to call a method on the element, the one added by the HTC script:
el.setValid(true);
However, the IE debugger gets sad and complains that setValid() is not a function. Inspecting it in the debugger confirms this:
typeof el.setValid // "unknown"
Of course, once the page has completed rendering (or whatever period of time is needed for the document to actually be ready has passed), the validation function works as expected (because I'm calling the same validation function on change and blur events as well). That is, when the function is called outside of jQuery's on-DOM-ready function, it works just fine.
Do any of you have any ideas at to what might be happening here? Is jQuery's "ondomready" being registered before the HTC script's "ondomready"? Can I somehow change that order?
I'm currently seeing this behavior in all versions of IE.
EDIT: WORKAROUND
I discovered a workaround. If you take the function call out of the jQuery ready function and throw it at the end of the page, it works (i.e.:)
...
<script type="text/javascript">
txtFiscalYearEndDay_Validate(document.getElementById('txtFiscalYearEndDay'));
</script>
</body>
</html>
I do not know if HTC counts toward page ready but i suspect they do not.
What you might try is check something that only is tru after the HTC hase finished.
You own script should then start something like this:
function MyFunction() {
if(!HTCIsreadyTest()) {
setTimeout(MyFunction, 100);
return;
}
//the rest of your code
}
This basically makes you function check and restart in 100 milliseconds if conditions are not met untill the test succeds.
You could also ad a counter argument increasing it by one for each attempt to have some timeout code trigger if HTC sciprts has not loaded after 2 seconds
The easiest workaround I could find was to move the validation function call out of the jQuery ready() callback and move it to the end of the page:
...
<script type="text/javascript">
txtFiscalYearEndDay_Validate(document.getElementById('txtFiscalYearEndDay'));
</script>
</body>
</html>
However, I found a more elegant solution. Because I seemingly need to wait for all page resources to be loaded, I simply needed to move the function call out of the jQuery ready() callback and instead put it in a window load() callback:
$(window).load(function() { // instead of $(function() {
txtFiscalYearEndDay_Validate(document.getElementById('txtFiscalYearEndDay'));
});
I'm using the latter so I can keep all of the JS code together.
I have probably a simple problem to solve but I don't know what's the right approach on that.
I have a div.notification bar on top of my website that is hidden by default. The bar does get an additional class of either success or warning that sets it to display:block; if needed.
So, there are two cases. Either an output message is rendered directly to the .notification bar on page-load (and it gets a class of success or warning right with it) OR the .notifcation bar is sliding down from top and is fed with json data.
Any way, the notification bar should always be visible for 10 seconds and than slide back up.
Therefore I wrote two functions that handle this bar.
var timing = 10000;
function notificationOutput(type, message) {
var note = $('.notification');
note.hide();
note.find('.message').html(message);
note.stop(true,true).slideDown().delay(timing).slideUp();
}
function notificationSlideUp(slideUp) {
var note = $('.notification');
if ( slideUp ) note.delay(timing).slideUp();
else note.stop(true,true).slideUp();
}
So the notificationOutput() function is triggered from various other functions that return json data and render that into the box.
And the notificationSlideUp() function is right now called on every page load because in my header I have this …
<script type="text/javascript">
$(document).ready(function(){
notificationSlideUp(true);
});
</script>
And there is a reason for that! Remember the case where the .notification is directly set to visible on page-load … e.g. when a user logs-in on my platform the .notification bar is immediately visibile and says "Welcome Username, you've successfully logged in".
I call the notifictaionSlideUp() function in my header to make sure the currently visible .notification bar will slideUp() again after 10 seconds.
And here occurs the problem …
Somehow this causes the entire notifcation timing and sliding up and down to be "confused". So there must happen some queuing of the slide-functions and or of the delay() function, because without the note.stop(true,true) in the notificationOutput() function the notification wouldn't slideDown() immediately if it's triggered within the first 10 seconds after the page load. That is because the notificationSlideUp() function has already triggered the slideUp() and the delay() of the object.
And the same happens to the delay. If a .notification is put out within the first 10 seconds the delay timing isn't right because the delay counter already started on page-load.
Any idea how to solve that so that it always works?
Update:
var notificationTimer;
function notificationOutput(type, message) {
var note = $('.notification');
note.hide();
note.find('.message').html(message);
note.stop(true,true).slideDown();
clearTimeout(notificationTimer);
notificationTimer = setTimeout(function() {
note.stop(true,true).slideUp();
}, 10000);
}
function notificationSlideUp(slideUp) {
var note = $('.notification');
if ( slideUp ) {
clearTimeout(notificationTimer);
notificationTimer = setTimeout(function() {
note.stop(true,true).slideUp();
}, 10000);
} else {
note.stop(true,true).slideUp();
}
}
Unfortunately, jQuery's delay() function doesn't offer any method for canceling a delay the way setTimeout() does with clearTimeout(). I'd suggest replacing your delay()s with named setTimeout()s, and writing a condition to clearTimeout() for cases in which you need to cancel/trigger a queued animation right away.
http://api.jquery.com/delay/
The .delay() method is best for delaying between queued jQuery
effects. Because it is limited—it doesn't, for example, offer a way to
cancel the delay—.delay() is not a replacement for JavaScript's native
setTimeout function, which may be more appropriate for certain use
cases.
But you can use the following 'hint' - replace delay with some animation which does not change anything. For example with .animate({opacity:1},timing)
I'm running into a little problem that's driving me crazy, and I'd welcome any thoughts as to the cause. At this point I feel like I'm just going 'round in circles.
I have the following code:
function JSsortTable(phase) {
dynaLoadingDivShow();
createSortArray();
dataArr = do2DArraySort(dataArr, orderList, orderDir);
sortArrayToRs();
dynaListTable.tableControl.refreshTableViaObjects(rsDynaList, colObjs);
dynaLoadingDivHide();
}
function dynaLoadingDivShow() {
document.getElementById('dynaReportGuiWorking').style.display = 'block';
document.getElementById('dynaReportGuiWorking').style.visibility = 'visible';
}
function dynaLoadingDivHide() {
document.getElementById('dynaReportGuiWorking').style.display = 'none';
document.getElementById('dynaReportGuiWorking').style.visibility = 'hidden';
}
<div style="visibility:hidden; display:none; z-index:25;" class="tableControlHeader" id="dynaReportGuiWorking">
Working...
</div>
I call JSsortTable as an onclick event. When I run the above code as is, I never see the div in question. The JSsortTable function takes some 800-2500 ms to run so it's highly unlikely I just missed it the 10+ times I tried. If I change the style of the div to start out visible, then it will remain visible until after JSsortTable has finished running and then disappear; exactly as expected. So I figured the problem was in dynaLoadingDivShow.
Now, I tried removing dynaLoadingDivHide to see what would happen and found something completely unexpected. The div will not appear when you the JSsortTable function fires. Instead, after all the other code has been run, when JSsortTable finishes, the div becomes visible. It's alomst as though IE (version 8) is saving up all the changes to the DOM and then waiting until the end to paint them. This is, obviously, not the desired behavior.
Anyone have any thoughts on this? I'm only allowed to have IE at work so I haven't tried this on other browsers. I have enough CSS/JS knowledge to be dangerous, but am by no means an expert yet. ;)
Thanks!
You'll need to use a timeout:
function JSsortTable() {
dynaLoadingDivShow();
setTimeout(JSortTableWork);
}
function JSortTableWork()
createSortArray();
dataArr = do2DArraySort(dataArr, orderList, orderDir);
sortArrayToRs();
dynaListTable.tableControl.refreshTableViaObjects(rsDynaList, colObjs);
dynaLoadingDivHide();
}
Note that I took out the parameter phase because it's not used in the function. If you do need the parameter then you'll need to modify the timeout as
setTimeout(function(){JSortTableWork(phase);});
and also add the parameter to JSortTableWork