Screen Blocking Code Required for Javascript/AJAX - javascript

Any good suggestions for a screen blocker when I want my AJAX call to be synchronous (thereby dissalowing a user to do anything until it is finished?)

When you use Synchronous-JAX (SJAX), you lose the benefits of AJAX, which in most (or all) cases results in bad user experience.
Instead:
Try using a modal window to shadow the other parts of the page while your UI of concern is in focus instead of locking the UI using SJAX. Although this is the most straight-forward approach and now is async, you would still lose the entire concept of async if you block the user from doing anything before the server responds.
A better approach would be to remove temporarily the handling function that calls the AJAX to prevent further action on the form/button/whatever while allowing operations to continue on other parts of the page.
For example, you have a form. You bind an event handler to that form that calls AJAX on submit. During submit, create some logic that removes that handler temporarily from the form or prevent it from calling AJAX so that further submits do nothing or maybe say "still processing/loading". After the server replies, reattach that handler to make it work.

Related

Does browser show HTML changes or allow submitting form while JavaScript is still running?

Given that JavaScript is running synchronously (no setTimeout) to add or remove HTML elements, are HTML changes supposed to be shown to the user before it's completely finished?
More importantly, if the JavaScript is changing elements that can be included in form submission (e.g. adding multiple textarea elements), can user click submit button while it's in progress and submit an incomplete request? (Some textarea elements are included in request and some textarea elements are not.)
Something like this:
<form action="" method="post"><input type="submit" value="Submit"></form>
And when a user submit it, some function happens to be in progress.
function happens_to_be_running_and_user_clicks_submit(){
the_form_element.insertBefore(document.createElement('textarea'),the_form_element.firstChild).value='first textarea value';
the_form_element.insertBefore(document.createElement('textarea'),the_form_element.firstChild).value='second textarea value';
}
(It seems there are a lot of discussion about reflow hurting performance. But I'm still not sure if there exists any requirement or maybe it just depends on the browser. Especially about submitting form, regardless of whether it has anything to do with reflow or rendering.)
I think your confusion can be explained by how you've named your example function happens_to_be_running_and_user_clicks_submit. I presume you expect that it is possible for a function to be running when a user clicks a button.
This is not possible. At least not without using web workers. And even then, web workers cannot alter the DOM so by the time the web worker sends a message back to the main thread to alter the DOM it becomes impossible again.
Javascript is single threaded. Therefore only one thing can happen at a time. When a user does anything (move a window around, click a button, move the mouse..) the OS will send that event to the application's event queue. Javascript (or rather, the browser) reads this queue to process events. But since it's single threaded it only processes events when it is not busy.
So. That leaves us with ONLY two possibilities.
Your function somehow executes immediately before the user clicks the button. Then everything the function does will be rendered and active when the user clicks the button.
Your function somehow executes immediately after the user clicks the button. Then nothing the function does will be active when the user clicks the button.
There is no 3'rd state. It's either all or nothing. At least not without something asynchronous like setTimeout or ajax.

Will dataLayer.push() definitely send data to google when triggered on an anchor?

This may seem like a simple question, but it doesn't seem to be answered anywhere that i can find.
I am writing an onClick event handler that simply calls dataLayer.push() when an anchor is clicked.
Is dataLayer.push() a synchronous operation?
Will the GET request to google definitely be sent, even though the browser has unloaded the page it was requested from due to the link being followed?
Some browsers show the connection get cancelled, some show it success.
My question is if the computer is slow, is it possible for the page to get unloaded before the request is sent?
This is why i assume that google started using the eventCallback property to redirect the user after the link has been followed.
e.g.
https://developers.google.com/tag-manager/enhanced-ecommerce#product-clicks
This source code does not include the click handler, but implies that the onClick event should stop propogation and let the eventCallback function set document.location.
However, as soon as you cancel the event, all its information has gone.
This (in my opinion) is just the wrong way to do it.
e.g.
(CTRL or COMMAND) + Click opens a new tab on browsers. This will not work unless the onClick event handler allows the prorogation to continue.
Relying on eventCallback also means that if the google scrips didn't load for one of the many reasons it could (but is still unlikely), your links don't work. And your site is broken.
So this leaves the correct way to do it for the onClick event handler to allow the event to propagate and return true.
Which also means that dataLayer.push() would need return after the GET request was sent for any of this to work properly.
Code example:
NOTE: You will get mixed results in mixed environments.
Link
$(document).on('click', 'a', function(event) {
// Is dataLayer.push() guaranteed to fire a GET ?
// data set externally
dataLayer.push(data);
return true;
});
Is there anyone out there that can guarantee that the GET request will get fired to the google server?
Have the google developers forgotten something here?
EDIT: Updated title to be more relevant to the question.
datalayer.push does not send anything to Google. It pushes objects with key/value pairs to the datalayer array. This might contain an event which in turn fires a tag. Whether the tag is sent depends on the setup of the tag, not on the dataLayer.push.
As a consequence, when you write your own click handlers your are yourself responsible to make sure your tags are actually fired.
If you use the built-in click handler you can configure a delay to make sure your tag has time to fire before the link redirects:
Since link clicks usually cause the browser to load a new page and
interrupt any pending HTTP request, you have the option to add a small
delay to allow tags fired by Tag Manager to execute properly before
redirecting to the next page. Checking the “Wait For Tags” option will
delay opening of links until all tags have fired or the specified
timeout has elapsed, whichever comes first.
You should be able to mix both methods (push data on the click, but still use the "native" link click handler for the event).
You can also try to specify "beacon" as the transport method in your Google Analytics tags, on browsers that support this (which I think is only Chrome at the moment) GA will then use the navigator.sendBeacon interface, which sends the data even in case the page unloads.
You might think that Google's solution is not very elegant (but the simple delay has the advantage that it works for all tags, not just for GA), but they have not "forgotten" the problem.
Also solutions that combine GA hit callbacks with timeouts that redirects if the callback fails as proposed i.e. by Simo Ahava somewhere should be be doable with GTM, even if they are probably more cumbersome to implement in GA.

With WebBrowser control, invoking a javascript function doesn't fire DocumentCompleted event

In my C# code, I'm using a WebBrowser control in a Form to display my data.
Initially I fill in my data through a
webViewer.DocumentText = someHtml; (1)
This one produces the sequence of Navigating, Navigated, and DocumentCompleted events, as expected.
Then at a later stage I make some calls to
webViewer.Navigate(new Uri("javascript:myFunction(x,y)")); (2)
Since I'm on the Compact Framework, I understand this is the only way to call some javascript. (as seen in this discussion)
Now, in terms of events, I only receive the Navigating event, and that's it..., not the other ones. WebBrowser.ReadyState will also stay at "Loading" forever. I'm a bit puzzled by this behaviour.
I've dumbed down myFunction to the simplest one to prove that this behaviour wasn't related to the actual content of that function (as if it was containing an endless loop or some critical errors).
While myFunction is indeed called, the ReadyState stuck in Loading state will prevent further updates of the DocumentText as done in (1), which prevents further normal execution.
I imagine I might have missed something about the use of this control, maybe there's a way to reset its state if it doesn't happen automatically, but I'm running out of ideas. Any hint?

How to trigger a delayed jQuery event?

I'm writing a workaround for web form. The given problem is that hitting Submit pops out a loading animation. The content is saved, but the form is still shown, as is the loading animation.
The idea is to trigger an event, 2-3 seconds after the Submit click, that will reset the form content and hide the loading animation.
How would you suggest to approach this?
Thank you.
Use the callback functions in the events to chain them together - that way it will make sure that the action has completed, instead of trying to run all of them at the same time. If you post some code we can probably help some more. There's also the .delay() function, but I think callbacks are more appropriate, because your process is event driven and not time driven. You have more flexibility in the case that something in the process goes wrong, instead of statically resetting after a click.
Can you just use a setTimeout(...) that calls a method that resets form content and hides the animation? See: http://www.w3schools.com/js/js_timing.asp
jQuery Form came to the rescue.
$('form#id').ajaxForm(function() {
// do stuff
});
This will run the callback after the form is submitted.

Javascript event synchronisation

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.

Categories

Resources