I have a web page that shows remote asset data (for example weather station data) and that does background XMLHttpRequest()'s every 5 seconds to our server and reloads the page if new data from the remote asset has been received. This has all been working fine for years.
The page also has numerous links and submit buttons that can be used to go to other pages or submit commands to the server (which then sends a command to the asset). Issue I'm having is that some of the commands the server then executes involve calls to 3rd party web services, some of which can occasionally take up to 30 seconds to return or time out. But in the meantime if new data came in from the asset the background JS function reloads the page, thereby interrupting and cancelling the new http request that the user initiated.
I could probably work around this by adding onclick or onsubmit tags to every link and submit button to call a function to disable the timer, but as there can be dozens of links on the page I am hoping there might be a simpler, more elegant way where one simple function can tell me if the user clicked on something and thereby initiated a new active http session.
I enable my script by doing a setTimeout('myCheckServerFunction("'+url+'")',5000); from the html head. If the server then tells it there is new data it does a setTimeout(function(){location.reload();},5000);
So I'd like to disable the JS timer and prevent any reload if the user has clicked any link or button and thus if a new http session is active. Does there exist a function like this? eg. something like "window.isNewHttpRequestActive()" ? Or maybe there's a way I can check if the window.location changed? (not sure if that would get updated before the new http request is complete.)
Otherwise I could maybe attach a addEventListener() to every link and submit button on the page but I'm a PHP dev not JS so if anyone could recommend the best way to parse the DOM and attach a listener to every link and submit button that would work too.
I did try looking for events that "bubble" up to higher layers eg. the body element and that will catch link clicks but also catches any click even just a click on any blank area, So not sure how well that would work as I'd still need to filter that event to determine if it actually came from a link or button. Thank you.
Listening to all click events on body isn't necessarily a bad idea.
EDIT: As gre_gor pointed out in comment, it might be. The perceived target of the click is not always the link or button if other elements are inside of them.
So my original method, which was using event.target.tagName is to be avoided.
The following code would add an event listener for click on every a element of the document, and let you cancel the timer if it is set :
for (let element of document.getElementsByTagName("a") {
element.addEventListener("click", (event) => {
if (relocationTimeout !== undefined) {
clearTimeout(relocationTimeout);
relocationTimeout = undefined;
}
});
}
Up to you to adapt the selector in the loop to fit your needs.
Of course don't forget to store the timeout reference in a variable when you set it :
let relocationTimeout = setTimeout(function(){location.reload();},5000)
Anytime I click on a link/button anywhere on my site that performs/calls a GET or POST (Ajax and non-Ajax), if it takes more then a few seconds I would like to display a loading gif. I know how to do this on an individual basis, but I would like to know if it is possible to create a function that will do this automatically and then hide the gif when finished (assuming it does not redirect to a new page).
I found this but this does not work with the post method for spring security for example.
It may be a case where it is not possible or requires more effort than it's worth. I would just like to know if it is possible and if so how might it be approached.
The only constraint is that any methods calling the post or get should not need to be aware of this so called "listener".
This is tagged jQuery so I'm giving a jQuery answer for simplicity. This is also solvable in a relatively simple manner without it.
Hooking on every request:
Let's say your method is called myMethod.
GET/POST requests may be triggered the following ways:
Form submits, in which case you can select the form $("#formID").submit(myMethod); . Note that if myMethod returns false it will cause your form to not submit
AJAX in which case you can use $.ajaxStart with $.ajaxStart(myMethod)
"a" tag clicks, and other click handlers, in which case you can perform $("a[href]").click(myMethod) , note that this selects all a tags with an href attribute, you might want to change the selector to suit your needs
Image loads which you can handle like explained in this question.
Script loads which you can detect like explained in this question.
Stylesheet/Link loads, which is explained in this blog post. You can add a hidden element to the CSS and check if the style was applied in an interval, and when it does call myMethod
What you can't do:
If your page has a plugin like Flash, or in general anything your JavaScript does not have access to, you can't hook on requests it makes.
The case of displaying a 'loading' gif.
From what you're asking it seems like you only care about image requests, and AJAX requests (correct me if I'm wrong), since external pages that take a long time to load NOT in an AJAX requests can (should) implement that .gif logic on the new page. This could be handled as I explained above.
Although you can hook every case, I would not do so. I would create a method that loads the 'loading' gif into a place and accepts a url. If that url is an image (for example, by file extension if that's ok with your mapping) use the logic in the image load detect linked question, if it's AJAX load the loading gif to where the data will be loaded, and replace it with the data on a .done() handler.
Here is a question about how to do this for an image, here is how to do it for AJAX . The two can be easily combined into a method which is what I believe you should use.
I'm writing a small website which has several pages that are very similar. Most of the time, only the content of one div is different. The navigation, header etc stays the same.
So I realized this with a "base" html file, some smaller html-files with only a content-div and javascript code like this (which is triggered by a button click event):
$.get("content/text1.html", function(data) {
$("#content").html(data);
});
This works very smooth but the problem was, that the url in the address-bar doesn't change with those kind of requests. So it is not possible for the user to link to certain pages. I know it is possible with #-urls, but i want to have urls like:
example.com/talks/foo/bar
And not some workaround.
In another Thread, someone gave me a hint to the html5 browser history api (especially history.js).
What I'm trying to achieve with it:
Someone clicks on a button -> an ajax request is triggered and the content of the content-div gets updated -> the url gets updated to something like example.com/talks/foo/bar
If someone requests example.com/talks/foo/bar in his browser directly, the same ajax request and content update as in (1) should be performed
I tried to realize the first one with:
$.get("content/text1.html", function(data) {
$("#content").html(data);
History.pushState(null, null, "content/text1.html");
});
But how am I supposed to achieve the second point? With a rewriterule, that redirects everything to the base-html file and some js-logic in it to decode the url and trigger the ajax request?
I have the feeling, that I am a bit on the wrong path..
So is this the way history.js should be used?
How can i achieve the second bullet point?
To get the initial state in html5 browsers no ajax calls are required. Like you said the url itself gets changed, not the hash so the server should reply to the url with the correct content already loaded.
You should do all your ajax calls and DOM manipulation inside the statechange event handler.
So when the user clicks on a link all you do is call pushState and handler the DOM changes in the statechange event handler. This works because statechange is triggered when pushState is called.
I am new to javascript and the whole front-end side of development.
Here is what I am using:
Java servlet running on Tomcat7
twitter-bootstrap for the layout/theme
Pubnub to keep track of how many times a form is submitted
Javascript/jquery to display this value on a webpage.
I have added the PUBNUB.subscribe callback which updates the value on the webpage just fine. However, when I first load the webpage, I don't know what value I should display.
Here is what I did to overcome this issue:
I added a method to the servlet that, when passed in the correct parameter in a POST request, it will send out a pubnub message with the amount to be displayed which is working fine.
Next, I tried to call a POST request using jquery like this:
$.post("../servlets/theservlet",
{
update : "true"
});
I tried placing that inside a $(window).load function but when I loaded the webpage, it did not do what I expected.
I expected it to do the POST after everything was loaded, which would cause the pubnub message to be published from the servlet, which would activate the callback method in the PUBNUB.subscribe function. However, the value didn't change, it stayed as the placeholder that is hardcoded in the html.
Currently, I am now calling setTimeout("updateUses()", 1500); from within the $(window).load function. updateUses() is the exact same $.post call I showed earlier.
Now when I load the page, the placeholder value is there for a little bit (seems longer than 1.5ms) and then it is updated to the correct value. If I remove the setTimeout and just call updateUses() directly, then nothing happens again.
What do I need to change so that it loads the value instantly (or at least without a noticeable delay)?
If the page builder is JSP and what I have just read is correct then you should be able to do something like this:
RequestDispatcher rd=application.getRequestDispatcher("path/to/pubnub/servlet");
rd.include(request,response);
If you choose to stick with the ajax approach then the javascript should look something like this:
$(function(){
$.post("path/to/pubnub/servlet", {update:"true"}, function(response){
//do whatever is necessary with the response here, eg.
//$("#myElementId").html(response);
});
});
The $(function(){...}) wrapper ensures the code inside it is executed at the earliest opportunity after the DOM becomes ready. Hence no need for a timeout. jQuery is typically written inside such a wrapper.
Is there a possible way to synchronize events in javascript?
My situation is following: I have a input form with many fields, each of them has a onchange event registered. there is also a button to open a popup for some other/special things to do in there.
My requirement is, that the onchange event(s) are finished before I can open the popup.
Any ideas how I can achieve that without using setTimeout?
EDIT: further explanation of requirements:
To clarify my situation I try to detail what I'm doing.
I got a form with some input items (order entry matrix form, e.g. article, serial#, count). Every time user changes data in one of the fields an ajax call is triggered by an onchange event to validate the user input and read additional data (e.g. presetting/formating one of the other fields). These ajax calls are heavy and cost time, so I have to avoid duplicate validations.
There is also a button which opens a popup which gives the user an other form to change data he entered before line by line, so it is absolutely necessary that all validations are done before this popup is opened.
At the moment I try to synchronize the onchange events and the popup opening using setTimeout (popup isn't opened before all validations are done), which causes problems at my customers site because these popups are trapped by the popup blocker.
So I need to open my popups without getting stopped by some popup blocker (IE 6/7/8).
Because of my matrix-form I just can't validate all input items before opening the popup, I need to validate only those which have been changed and are not validated yet (should be at most 1).
It sounds like you are doing form validation, with an automatic popup when the form has been fully completed. To do that, you write a single validation function in javascript that checks every field on the form. You can fire this function from each of your OnChange events, and have the function open the popup when the entire form successfully validates.
Consider checking out jQuery, when you have a little free time.
http://jquery.com/
you can set up a little callback to your onchange events to insure that all of your validation occurs before the popup.
function onChange(callback)
{
// Do validation
// Call the callback
callback();
}
function showPopup()
{
// Show the popup
}
Then on your onchange call just call
onChange(showPopup);
If you set a global variable and use setTimeout to check if it is set properly. Depending on how complex the situation is you can either use a boolean, two booleans, a number that increments, or even an object. Personally I would proly use an object as that way I know which one hasn't fired yet. something like var isDone = {username: 0, password: 0, password2: 0};
Let assume by input fields you are meaning only text inputs and not any checkboxes or comboxes( I'm guessing you are trying to make a sort of auto-completion).
My advice is to use onkeyup and onkeydown.
var keypressed = false;
function onkeydown( )
{
keypressed = true;
}
function onkeyup( )
{
keypressed = false;
setTimeout( function()
{
if (!keypressed)
show_popup();
else
setTimeout( this.calee,1000)
}, 1000 );
}
Set flags (variables) for each group of validations.
Initiate the flag at 0.
Set the flag to 1, when
validation is complete for the group.
When the user pops the button, if all
flags are 1, popup the window.
The callback that Jon mentioned would solve the problem of "what do you do if they are not yet all validated?"
EDIT: Added after clarification:
Have you considered adding the popup button, via DOM methods (easy) (or innerHTML, if you like), after everything is validated? That way, there is no option shown before its time. :D
Also, do you test if a popup is blocked? If it is, you could branch to either a notice to the user that their blocker is blocking the editor; or to loading your editor into an iframe automatically; or to loading the editor to the main page via DOM methods (appending documentFragment, etc.).
Some blockers give users the option to block even popups generated from clicking on links (which were traditionally off limits to blockers). I would think you would benefit from some kind of a backup method, or at least a warning system in place regardless.
HTH
i don't think i have completely understood your question, but here are some thoughts on solving problems you may have :)
first, i'd deactivate the popup-opening button when the ajax call is sent. then, when the requested data arrives and all validation is done, activate it again. you can do this with a counter: increment it for every sent request, decrement it as soon data arrives and validation is completed. activate the popup opening button when data arrives and the counter is zero. this prevents the user from clicking the popup opening button while there are still validation requests pending.
you can use the same technique for the input fields themselves: lock the input fields that await validation by setting them to readonly, unlock them when everything is done.
to prevent problems when the user changes form values while the ajax call hasn't yet returned, you have several options:
use a timer for sending the request: everytime an onchange event is fired, wait x seconds before sending the request. if another onchange event happens before the ajax request is sent, reset that timer. this way, several onchange events withing a certain timeframe trigger just 1 ajax request. this helps reducing load.
you can calculate and store checksums for every position, so if an onchange event is fired, calculate the checksums again and compare them. this way you know which parts really have been changed, avoiding unnecessary validation requests.
also, never bet on time (if i understood the settimeout stuff right). x seconds may be enough under normal circumstances, but in the worst case ...
We needed something similar for a wizard where some steps required AJAX validation. The user wouldn't be allowed to close the wizard by clicking Finish if there were any pending validations. For this we simply had a counter for pending validations, and a flag to signal if the user was wishing to close the wizard. The basic algorithm was:
If a new AJAX validation is initiated, increment the "pending" count.
When an AJAX validation returns, decrement the "pending" count.
If, upon decrementing, the pending count reaches zero, check the "finish" flag; if it is set, finish the wizard.
When the user clicks Finish, check the "pending" count; if it's zero, finish the wizard; it it's non-zero, set the "finish" flag.
This way, synchronization can be handled with just two variables ("pending", "finish").
I strongly advise against using multiple flags for each different AJAX operation; a state machine usually gets out of hand when states are tracked with multiple state variables. Try to avoid it unless it's absolutely necessary.
I also don't suggest using setTimeout to arbitrarily wait until desired conditions are met. With the counter approach above, your code will act on changing conditions, as soon as they change.