Universal code that disables buttons onclick - javascript

I have a next issue:
My application contains many buttons that make async requests to the server, currently if user is fast enough to click button more than one time - same request gets executed twice or more and data on the server gets duplicated.
Is there a way to disable clicked button, until the request is executed?
Someone suggested this solution:
$("input[type='button']")
.each(function () {
var el = $(this);
var onclickFunction = el.attr('onclick'), alreadyChecked = el.attr('clickHandler');
if (typeof onclickFunction != 'undefined' && typeof alreadyChecked == 'undefined')
{
el.removeAttr("onclick");
el.removeAttr("onclickFunction", onclickFunction);
el.attr('clickHandler', 'true');
el.on('click', function()
{
el.attr("disabled", "disabled");
$.when(eval(onclickFunction)).then(function () { el.removeAttr('disabled'); })
})
}
});
But if i understood correctly, this code runs only once. So if my application contains many views, this code should be executed on each view load.
Is there any more apropriate solution?

Two ways.
1) Use a flag(let's call it requestInProgress) in the page scope that is turned on once the request is made. Once the request is completed, turn off the flag.
2) Disable the button once the button is request is getting processing so as to prevent user from hitting it a second time. Enable the button once the request processing is complete.

Try using .one()
function handleClick(e) {
// not necessary, though notifies user button is disabled
$(this).attr("disabled", true);
// do ajax stuff
$.ajax().then(function() {
$(e.target).removeAttr("disabled")
// reattach `click` when ajax completes
.one("click", handleClick)
})
}
$("input[type='button']").one("click", handleClick)

What I would recommend is using a CSS class to prevent the user from multiple submissions. This also provides you the flexibility of easily styling the appearance for disabled buttons as well, say for their color or opacity in your stylesheet.
Something like this:
function onClickHandler() {
var myButton = $(this);
// check to see if it's already disabled
if (myButton.hasClass('disabled')) {
// if so, just exit out
return;
}
// add the disabled class
myButton.addClass('disabled');
// continue with your processing...
}
If browser compatibility is not an issue, you could also check out the disabled attribute, but I'm personally a bigger fan of using a class.

Related

Stop onclick method running with jQuery

I have a button similar to below
<button id="uniqueId" onclick="runMethod(this)">Submit</button>
What I'm trying to do is stop the runMethod from running, until after I've done a check of my own. I've tried using the stopImmediatePropagation function, but this doesn't seem to have worked. Here's my jQuery:
$j(document).on('click', '#uniqueId', function(event) {
event.stopImmediatePropagation();
if(condition == true) {
// continue...
} else {
return false;
}
return false;
});
Note: runMethod basically validates the form, then triggers a submit.
What you want to do, especially in the way that you want to do it, requires a some sort of workaround that will always be a bit fiddly. It is a better idea to change the way the button behaves (e.g. handle the whole of the click event on the inside of the jQuery click() function or something along those lines). However I have found sort of a solution for your problem, based on the assumption that your user will first hover over the button. I am sure you can extend that functionality to the keyboard's Tab event, but maybe it will not work perfectly for mobile devices' touch input. So, bear in mind the following solution is a semi-complete workaround for your problem:
$(document).ready(function(){
var methodToRun = "runMethod(this)"; // Store the value of the onclick attribute of your button.
var condition = false; // Suppose it is enabled at first.
$('#uniqueId').attr('onclick',null);
$('#uniqueId').hover(function(){
// Check your stuff here
condition = !condition; // This will change to both true and false as your hover in and out of the button.
console.log(condition); // Log the condition's value.
if(condition == true){
$('#uniqueId').attr('onclick',methodToRun); // Enable the button's event before the click.
}
},
function(){
console.log('inactive'); // When you stop hovering over the button, it will log this.
$('#uniqueId').attr('onclick',null); // Disable the on click event.
});
});
What this does is it uses the hover event to trigger your checking logic and when the user finally clicks on the button, the button is enabled if the logic was correct, otherwise it does not do anything. Try it live on this fiddle.
P.S.: Convert $ to $j as necessary to adapt this.
P.S.2: Use the Javascript console to check how the fiddle works as it will not change anything on the page by itself.
Your problem is the submit event, just make :
$('form').on('submit', function(e) {
e.preventDefault();
});
and it works. Don't bind the button click, only the submit form. By this way, you prevent to submit the form and the button needs to be type button:
<button type="button" .....>Submit</button>
Assuming there's a form that is submitted when button is clicked.
Try adding
event.cancelBubble();
Hence your code becomes:
$j(document).on('click', '#uniqueId', function(event) {
// Don't propogate the event to the document
if (event.stopPropagation) {
event.stopPropagation(); // W3C model
} else {
event.cancelBubble = true; // IE model
}
if(condition == true) {
// continue...
} else {
return false;
}
return false;
});
Your code is mostly correct but you need to remove J:
$(document).on('click', '#uniqueId', function(event) {...
You also need to remove the onClick event from the inline code - there's no need to have it there when you're assigning it via jQuery.
<button id="uniqueId">Submit</button>

Capture all click events and discard unallowed

I develop a web GUI for a special tablet. This tablet is running with Linux and the used browser is Chromium. The application is a web application with PHP, HTML5, JQuery and JavaScript. Now I run into a problem. The screen is a touchscreen and the user is able to navigate through the application by touch the screen. However now we decided to add a feature for saving electricity. This feature will shutdown the background light after three minutes. To turn on the backlight again, the user should touch the screen again. This leads to this problem, because on any touch the buttons are also pressed even if the background light is shutdown. I want to prevent this by discarding all clicks on the touchscreen if a cookie is set. If this cookie is not set the touchscreen and the application should work as desired. How can I solve this problem?
I installed an event listener to register all clicks and to reset the time.
window.addEventListener('mousedown', function(e){
$.get('php/timeupdate.php', function(){});
}, false);
Code used to stop the execution:
$(document).on('click', function(event) {
$.get('php/getwakeup.php', function(e){
if(e==='true'){
//event.preventDefault(); // I tried all three possibilities
//event.stopImmediatePropagation();
event.stopPropagation();
}
});
});
You can try this:
$(document).on('click', function(event) {
// get your cookie
if( cookie is set ) {
event.stopPropagation();
}
});
event.stopPropagation(); stops every event handling from where you called it =)
EDIT:
You have to set your $.get call synchronous or do it completely diffrent. Take a look at the jQuery.Ajax documenation. There is a parameter called "async".
But be careful unless the call is ready nothing else will be executed on you page! So if your script doesn't answer nothing else will work on your site.
The better solution would be setting ja recurring call that will get the information you need. Set it to every two seconds (setInterval is your friend here). If your response is true than set a global variable that you can check in your onDocumentClick event.
window.isBacklightOff = false;
setInterval(function() {
$.get('php/timeupdate.php', function(e) { window.isBacklightOff = !!e; })
}, 2000);
$(document).on('click', function(event) {
// get your cookie
if( window.isBacklightOff === true ) {
event.stopPropagation();
}
});
When the back light goes off you can set some flag handleEvents=false;
So when the flag is on don't handle any events.
Now when the back light is on you can set handleEvents = true.
$(document).on('click', function(event) {
// get your flag say handleEvents
if( !handleEvents ) {
event.stopImmediatePropagation();
return;
} else {
//do your biz logic send ajax..etc
}
});
Reason why your code above is not working:
$(document).on('click', function(event) {
$.get('php/getwakeup.php', function(e){
if(e==='true'){
//event.preventDefault(); // I tried all three possibilities
//event.stopImmediatePropagation();
event.stopPropagation();
}
});
});
The function inside $.get is async and called on success in that you are setting the event to stop propagating...well by that time when the success function is called the event is already complete and has called all the listeners.
So in short you must not do the event stop propagation inside the success function.

Warn user about unsaved changes to a form, when a form is being replaced during an AJAX call?

I'm new to Javascript and JQuery, and I'm implementing a warning to users that displays when they have made unsaved changes to a form's input/select/textarea elements if they navigate away from a page. I currently have the following which works fine when they leave a static form page:
/*
* Warn users when leaving a page with unsaved content, watches elements: (input, textarea, select) unless
* they are tagged with the "noWarning" class
*/
$(document).ready(function() {
$(document).on('change', 'input:not(.noWarning),textarea:not(.noWarning),select:not(.noWarning)', function () {
window.onbeforeunload = function(e) {
return 'You have unsaved changes';
};
});
});
The only page where it does not work, is in our main editing page. This page, unlike the others, has multiple tabs for editing different aspects of an item, which when clicked, trigger an AJAX call which replaces the content div with the appropriate form for editing the different aspect.
No warning dialog is displayed when a user clicks on a tab though, so any unsaved changes to the input are lost.
My intuition is that because the url is not changing, onBeforeUnload() is not executing. So I would have to check for any changes directly in the function which handles the AJAX call for replacing the form when a tab is clicked:
function clickedTabbedMenu() {
// This function replaces the content div with a new div and form
}
So my question is, how do I go about checking if any changes have been made to the elements in the current form before I replace the content div with another??? Can I directly call the "change" event listener for a true/false??? Or perhaps a different approach to handle this page's warning messages?
Any help is appreciated
Attach a change event handler to all the elements of the form. Have a variable outside the handler's scope dirty (or even a data on the form element) be set to false when a form is loaded, and true on every change event. Then, before replacing the form, check if dirty.
This would also be a good strategy for your non-AJAX pages as well - instead of setting the whole onBeforeUnload each time an element changes, just set onBeforeUnload once, and check if dirty inside it. This makes handling your AJAX and non-AJAX pages very similar.
EDIT: Untested because it's late and I need bed, but basically:
$(document).ready(function() {
var dirty = false;
$(document).on('change', 'input:not(.noWarning),textarea:not(.noWarning),select:not(.noWarning)', function () {
dirty = true;
});
function checkDirty() {
if (dirty) {
alert('You have unsaved changes');
return false;
}
return true;
}
// for non-AJAX pages
window.onbeforeunload = function(e) {
return checkDirty();
};
// for AJAX pages
$('.ajax_navigation_tab').on('click', function() {
if (!checkDirty()) {
// do the ajax thing
dirty = false;
}
});
});
I would try checking for and calling window.onbeforeunload() in your ajax script.
If it exists and returns a string, use it as an error message and halt the operation :)

JavaScript to check for specific events

I have a Wizard on my page, and for one of the WizardSteps I have some JavaScript to enable / disable controls based on radio button selection.
This works fine in the first instance, however I also have a button which adds a row to a grid (and that row has a Remove link). If I click the button, or the Remove option, then it does what I can only describe as a partial postback of the page and any disabled controls will now be enabled.
I've tried to catch anything on PostBack, but this doesn't actually get fired which is why I've described it as a partial one.
Is there an event in JavaScript that I can catch for this? I figure if I can catch an event then I could try and make the controls enabled states persist.
EG I've tried to put some code to catch when the state changes for the control itself, but this doesn't fire.
var myControl = document.getElementById('mainContentPlaceHolder_myWizard_myControl');
if (myControl != null) {
myControl.onchange = function () { DisableControl(this); };
}
function DisableControl(myControl) {
// This actually does a lot more, but this is just for the purposes of showing some code.
myControl.enabled = false;
myControl.disabled = true;
}
try this functions:
<script>
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(function() {
//start request
});
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function() {
//end request
});
</script>

Making an Ajax form from an Ajax request in jQuery

The client is making a request to the server.
I need to take part of that request, and make the form button work with Ajax.
This piece of code works perfectly for links:
var pagination_render = function() {
var pagination = $('.pagination a');
pagination.each(function() {
$(this).click(function(event) {
load_server(this.href, '.houseindex');
return false;
});
});
};
pagination_render();
I tried numerous things for making the Ajax button work, and this is one of the tries:
var contact_user = function () {
$('.expanded').find('#submit').each(function() {
$(this).unbind('click');
});
$('.expanded').each(function() {
$(this).find('#submit').click(function(event) {
form_submit($(this).parent(), '.contactuser .msg');
return false;
});
});
}
Whenever there is a successful Ajax call, it goes through all of the expanded items, and then binds a click event.
Now, sometimes this code works, and sometimes it doesn't.. When it doesn't work, it disables other events (toggle links) I have set up.
It seems as if I need to wait a few ms for it to load the component into the DOM.. Do I?
So I get that when you call contact_user you:
First unbind any previous binded click events from the submit button. I see one possible problem there and is that you are looking for an id of #submit. You should only have one id in a single page. Therefore you only need to use $('#submit').each(...) or if you have several submit buttons in the page either use a class if there are several submit buttons inside an .expanded item or just use $('.expanded :submit')
Adding a custom event when clicking the submit button. Same thing, you can simplify this by $('.expanded :submit') or if you truly only have one button with an id of submit (quite confusing). Go with $('#submit').
In conclusion:
var contact_user = function(){
$('.expanded :submit').unbind('click');
$('.expanded :submit').click(function(){
form_submit($(this).parent(), '.contactuser .msg');
return false;
});
};
the :submit selector will select all <input type="submit" />.

Categories