Javascript direct confirm() function replacement - javascript

I would like to replace the Javascript confirm() function to allow custom buttons instead of Yes/Cancel. I tried searching but all the solutions are event driven such as jquery dialog(where the code does not wait for a response but it is event driven). Does anyone know of a non-event driven solution. It must work in Safari as well as IE (so no vbscript).
Here is sample code in many parts of my system. This is old code and was not designed with event driven windows in mind. I am trying to avoid a rewrite.
**
// Wait for users response
if (result>2000) {
if (confirm("Are you sure this is right?")){
... do stuff
}
}
... continue with other stuff
... lots of other code.
if (confirm("Did you double check your numbers?")){
... do more stuff
} else {
... do something
}
**

Like the others have said, this isn't possible. confirm is a blocking function - no more script is executed until the user has dismissed the dialog - and you can't simulate that with other methods of Javascript.
A better solution would be to structure your code for asynchronous execution. This is almost always a better idea -- firstly, it lets you decide how your dialogs should look, what buttons there are, etc; and secondly, it doesn't block the user. They might have the important information they need to double-check open in another tab, or elsewhere on the page. With confirm they'd have to answer your question before being able to get to either of these places.
Here's a snippet of what the code might look like. There's a lot of blank bits here, but it might put you on the right track:
if (result>2000) {
displayConfirm("Are you sure this is right?", {
"Yes": function () {
// ... do stuff
},
"No": function () {
// do.. nothing? up to you.
}
}
}
You'll see here that there are two functions defined, but none actually get executed. The displayConfirm function would have to construct a dialog box (in whichever way) and then create buttons, using those functions as the click handlers (or at least, calling them from the click handler).

What you're trying to do is impossible. You'll have to use an event driven custom dialog solution, or stick with the browsers default confirmation dialog.

You will not be able to do this w/o changing your calls. No custom code can stop execution like the confirm box can. Any solution will require editing code to an event model.

As others have mentioned you can't do it directly, but I managed to do it in a round about way. Assuming like me you have a HTML button which submits a form, and want that button to have a jQuery modal dialog...
add an onclick event to the HTML button
make the onlick event open a jQueryUI dialog, and have the onclick event return false to cancel the button's default action
On your jQueryUI dialog, get the Yes/Ok button to remove the onclick event from the button in step 1, and then call then trigger the button to fire the click event

Related

onChange event firing incorrectly after being loaded programmatically

I have an APEX application where there are many drop down items. I've bound change event handlers to them using the bind function of jQuery.
Now when I load the content of a drop-down programmatically using $('#ELEMENT').trigger('apexrefresh'), the drop-down reloads but the change event handler fires automatically.
How do I prevent this from happening? I tried avoiding binding the event handler using bind and instead adding the onChange attribute to the element. The incorrect behaviour was still present.
Here is the skeletal code:
$(document).ready(function()
{
$('#P7021_MSG_DEF').bind('change', function(e)
{
console.log('bound function onChange() msg_def');
updateStartWord();
}
);
});
function updateMsgDef()
{
console.log('function updateMsgDef() ');
$('#P7021_MSG_DEF').one('apexafterrefresh', function()
{
if( $x('P7021_RESTORE_CHK').value == 'Y')
{
setdefault('P7021_MSG_DEF', vJson.msg_def);
}
updateStartWord();
}
).trigger('apexrefresh');
}
In the above code, when the updateMsgDef is called from another function the function updateStartWord() gets called twice - once by updateMsgDef() itself and again by the onChange handler that was bound to P7021_MSG_DEF item.
If anyone could help on this?
Calling $('#ELEMENT').trigger('apexrefresh') is going to trigger the change event. Short of going back to the drawing board altogether, the solution is going to be a hack whatever you do. You could poke about in (and quite possibly break) Oracle's javascript. You could write your own AJAX to populate the select list.
The easiest way might be to check in your onChange event which element currently has focus, eg:
onChange = "if($( document.activeElement).attr('id')=='YOUR_PAGE_ELEMENT')
{ $( document.activeElement).trigger('apexrefresh'); };"
If the user has changed the select list, it should still have focus. There's no guarantee that will work in all browsers, but I think it should be ok in current Chrome and IE versions.
I've been in a similar situation to yours, and have come to accept that if the page logic is too complicated to implement using DAs, maintaining it is likely going to be a nightmare whatever happens. Much as I like "proper" programming, Apex is really all about the declarative controls.

Postback not triggered after javascript on change event

In my asp.NET application I have implemented a control to validate forms input data using server side logic.
The idea is to drag the control to wherever it's needed, set it up in the code behind and the form will be validated.
This validation occurs on the onchange event of each field and on form submission - synchronous ajax call to the server side.
This was working fine until I published it to IIS.
The problem is the following: the user is writing something in a textbox. Then, with the focus on that textbox, clicks on a button or linkbutton, not related to the form being validated.
The validation ajax call occurs (jQuery onchange fires) and the button postback is not reached. Through debugging I found the problem to be the ajax call is somehow preventing the postback to fire (almost feels like a synchronism problem).
I reduced the problem to the point that an alert seems to be causing the same thing as the ajax call. Please have a look at the following project: EDIT: Link removed because I can't post more than 2 links on the same post - sorry!
Consider the first 2 textboxes and the button:
1) If you write something on the first, then click the button: the onchange fires, an alert is shown and the postback does not occurr.
2) If you write something on the second, then click the button: the onchange fires and the postback occurrs.
Can someone please explain why this behavior happens and if there's any solution to this, ie, make the postback fire after the javascript finishes running?
I can think of 2 ways to solve my problem but I need to know (inside the textbox change event) the ID of the control clicked by the user. Any way of getting it?
That way I could: trigger the control explicitly OR verifiy if it doesn't belong to the form controls and don't event validate the input in that moment (that would make sense).
Thanks in advance.
EDITED 22-10-2014:
The plot thickens. This seems to be a synchronism problem. Check this other test application where I removed the alerts (this concentrated too much attention and is not actually related to the issue as I'm not using alert boxes in my project - I'm using little balloons) and just left the AJAX call.
Now, on the server side (WebMethod) I put a Thread.Sleep(). If the thread sleeps for too long, it seems to miss the postback. In my case, on my development environment, the threshold seems to be 80ms. If the ajax call takes less than ~80ms, then the postback is done, if it takes more than that, it misses the postback. Any ideas or similar (resolved) issues you have seen? Note that my ajax call has async: false.
EDITED 24-10-2014:
Finally had another look into this. I think I may have come to a possible solution, although I don't like the idea of relying on a setTimeout to handle the submit button 'click' before the 'focusin' (same control).
I changed the logic (still achieving the same goal) and now use different events.
Now I need to distinguish when the submit control fires the 'focusin' event because it just gained focus (1) or it was clicked (2):
The user could just be tabbing (validates the last field that had focus - if it belongs to the form being validated)
The user could have clicked (does not validate the last field that had the focus, but the whole form and then submits or not)
Have a look at this new test app which is closer to what I have in my project.
Can you help me finding a better way to handle/process the click event before the focusin event on the same control without something unpredictable like a setTimeout? If I do need to rely on the setTimeout, how much do you think the wait should be set to? On my machine 150ms works, but on another persons, it may require more time? Something like some sort of callback would be ideal.
Thanks again
Use __doPostBack('',''); at end of your javascript function
It does appear that an alert box stops postback in this situation. The sensible solution I found was to use a jQuery dialog which doesn't seem to suppress a postback. Problem is of course the dialog doesn't persist itself through the postback but this is solved by a hidden field containing a 'flag' to display the dialog after postback or not.
You will need to add jquery-ui.js and some style for the dialog, if this is a serious application I suggest you download both files and put them in scripts folder as you already have with the jquery min.
<head runat="server">
<title>Postback with dialog</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
<script src="scripts/jquery-1.8.2.min.js" type="text/javascript"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#TextBox1").on('change', function(e) {
$("#doDisplayDialog").val("yes"); // Add a flag so it shows after postback.
$('#jqAlert').dialog({
closeOnEscape: true,
open: function(event, ui) {
$(this).parent().appendTo("form");
}
});
});
if ($("#doDisplayDialog").val() == "yes") {
$('#jqAlert').dialog({
closeOnEscape: true,
open: function(event, ui) {
$(this).parent().appendTo("form");
}
});
$("#doDisplayDialog").val("no"); // Clear the flag so it doesn't display after postback.
}
});
</script>
</head>
Add a hidden field:
<asp:HiddenField ID="doDisplayDialog" runat="server" />
And a Div to be the dialog box:
<div id="jqAlert" title="Alert" style="display: none;">
<p>Postback will happen!</p>
</div>
Code is based on your downloadable test website application.
-- not a working solution below --
Try this - copy/paste replace these lines in your test web application:
$(document).ready(function() {
$("#TextBox1").on('change', function() {
alert('T1 Postback does not fire');
return true;
//return AjaxCall();
});
$("#TextBox2").on('change', function() {
alert('T2 Postback does not fire');
return true;
//return AjaxCall();
});
});
The only change I did was replace single quotes with double quotes in jquery selector here
$('#TextBox2')
with
$("#TextBox2")
Edit: actually it doesn't work, I had a bug in my test code. Will look more into this.

how to fire a callback before redirect?

I want to write a global method for my site.
That when the page jumps to another, before the redirection acts, show a waiting mask on the page.
So I'm wondering if there is some way to get an event before the redirect?
The following code explains what I want to do, but doesn't work.
$(function() {
$(document).on('before_redirect', function() {
// show the waiting mask.
});
});
The answer can not be so neat, I just want the GLOBAL METHOD, once this piece of javascript included, no need to write anything other place.
Pray for good solution!
What you want is the beforeunload or unload event. JQuery also provides the unload shorthand method (deprecated after 1.8). Different browsers handle these events inconsistently, so you'll want to test each and make sure that your solution is acceptable in each. Generally, you'll lose control of the window once you've allowed the request to proceed so a mask may or may not work as intended.
the simplest way is place the same class name on redirecting elements like buttons ,anchor tag like so and write code based on class.
Html
<a class="navigation" href="/nextpage"></a>
or
<button class="navigation"></button> //for this you need to put url onClick function
js
$(function() {
$(document).on('click', '.navigation', function() {
// show the waiting mask.
});
});

Intercept form onSubmit

Is there any way we can intercept the html form's onsubmit event?
In my web application, there are several screens containing forms etc. The issue we are facing is when the user presses any button multiple times, the server gets overloaded with same requests.
Some of the forms have event handlers already attached to them(like onSubmit, button.onClick etc).
One way can be to "inject" my button disable code by going through all the screens.
But what I am looking for is a generic solution which can be applied to all the screens by just including the script where the function is written.
I know I can setup callback using jQuery (capturing onSubmit for form), but in the issue in this case is if any screen has a onSubmit registered already, it may not get called.
Any help in this regard appreciated!
I think this piece of code is a good place to start. It should be placed in separate file and included where you want to use it (if you appear to have global list of scripts - its a good place for it)
var suppressed_items = [];
function allowOnlyOne(item,e){
if (jQuery.inArray(item, suppressed_items)==-1){
//hi little item, I haven't saw you before, please go on... but I remember you
suppressed_items.push(item);
return true;
}
else{
//Hey, you have been submitted already, stay where you are!
return false; //or e.preventDefault(), it's a matter of faith :)
}
}
jQuery(document).ready(function(){
//don't worry, it won't replace your `ready` handlers, but just append new handler
jQuery("from").submit(function(e){
return allowOnlyOne(jQuery(this),e);
});
});
You can use the allowOnlyOne function with any item you wish. So, for example to allow single click on all hyperlinks, inside that ready handler add:
jQuery("a").click(e){
return allowOnlyOne(jQuery(this),e);
}
I hope you get the basic idea: catch the event, get the ID of the element that trigger it, fed it to AllowOnlyOne along with event.
Of course you can wrap it all around into self-executing closure to achieve incapsulation and so on...
If you already have jQuery I suggest you use it... All you need to do is make sure is that your form's onsubmit do not have a "return false" or else it can block jQuery's on submit.
Here's what you need to do:
Remove any return false from your form's onsubmit (if any). Don't worry we'll take care of this later in jQuery.
Add a class to your forms... something like "disableOnSubmit". Example:
<form action="something" onsubmit="yourExistingCode" class="disableOnClick">
</form>
OR
<form action="something" onsubmit="yourExistingCode" class="someOtherClass disableOnClick">
</form>
Implement a code similar to:
<script type="text/javascript">
$(document).ready(function(){
$('form.disableOnClick').submit(function(e){
// preventDefault() does the same as "return false;". It
// will not submit the form. If you're not using return false
// and want the form to be submitted remove the line below
e.preventDefault();
// Now diable any submit button
$('input[type=submit], button[type=submit]').attr('disabled, 'disabled');
});
});
</script>

Need to cancel click/mouseup events when double-click event detected

How is this done?
This is a good question, and I actually don't think it can be done easily. (Some discussion on this)
If it is super duper important for you to have this functionality, you could hack it like so:
function singleClick(e) {
// do something, "this" will be the DOM element
}
function doubleClick(e) {
// do something, "this" will be the DOM element
}
$(selector).click(function(e) {
var that = this;
setTimeout(function() {
var dblclick = parseInt($(that).data('double'), 10);
if (dblclick > 0) {
$(that).data('double', dblclick-1);
} else {
singleClick.call(that, e);
}
}, 300);
}).dblclick(function(e) {
$(this).data('double', 2);
doubleClick.call(this, e);
});
And here is an example of it at work.
As pointed out in the comments, there is a plugin for this that does what I did above pretty much, but packages it up for you so you don't have to see the ugly: FixClick.
Raymond Chen has discussed some of the implications of single-versus-double clicking - although he's talking in the context of Windows, what he says is relevant to browser-based UI design.
Basically, the action taken on a double click should be a logical thing to do after a single click. So for example, in a desktop UI, single click selects an item, and double click opens it (e.g. opens the file, or launches the application). The user would have to select the file to open it anyway, so it doesn't matter that the single click action is taken before the double click action.
If you have a UI component whose double click action is completely unrelated to the single click action, such that it becomes necessary to prevent the single click action from occurring once the system realises it was actually a double click, then you really ought to rethink your design. Users will find it awkward and counter-intuitive, in that it will not act in the way they are used to things acting.
If you still want to go that way, then you will either have to use the debouncing technique (in which case all single click actions will be delayed) or else implement some mechanism whereby the double click handler undoes the work done by the single click handler.
You should also be aware that some users set a very long double click time. Somebody with, for example, arthritic hands might have a double click time of more than a second set in their system preferences, so the debouncing technique based on some arbitrary time period of your choosing is going to make your UI component inaccessible to those people if taking the single click action precludes taking the double click action. The "undo what just happened on single click" technique is the only viable workaround for this, as far as I know.
The technique outlined in the other answers is known as debouncing.
jQuery Sparkle provides a clean elegant solution for this, by implementing a singleclick custom event. By doing this, you can use it just like any other event, so:
$('#el').singleclick(function(){});
// or event
$('#el').bind('singleclick', function(){});
It also provides custom events for the last and first clicks of a series of clicks. And the lastclick custom event actually passes the amount of clicks back! So you could do this!
$('#el').lastclick(function(event,clicks){
if ( clicks === 3 ) alert('Tripple Click!');
});
You can find the source code for defining the custom event here.
It's open source under the AGPL licence, so you can feel free to grab what you need out of it worry free! :-) It's also actively developed on a day to day basis so you will never be short on support.
But most importantly it is a DRY Plugin/Effect Framework to allow you to develop plugins and extensions much more easily. So hope this helps to achieve that goal!
If this is for a button submitting a form (which is not necessarily the case for the original poster, but may be the case for other people getting here via Google), an easier option would be to disable the element that is being clicked on in your click event handler:
$(selector).click(function(e) {
$(this).prop('disable', true);
}

Categories