I'm using formio with angular to render a custom form I've built - https://help.form.io/developer/info/angular/
I'm using the following to catch the submission and call my own logic, however the submit button stays disabled. I'm not actually using the formio server side so how do I re-enable the submit button without changing the source code? Is there an undocumented event for form submission success? I've tried also binding to 'formSubmission' event.
$scope.$on('formSubmit', function(err, data) {
event.preventDefault();
submitForm();
}
For anyone else struggling with this you can call 'submitDone' but you need to $broadcast from your controller, not $emit ( $emit goes up the $scope chain, broadcast goes down )
$scope.$on('formSubmit', function(err, data) {
event.preventDefault();
submitForm();
}
function submitForm() {
var error = doStuff();
if ( error ) {
$scope.$broadcast('submitError', error);
} else {
$scope.$broadcast('submitDone', 'Success');
}
}
if you are using pure javascript, trigger the event with "emit" and intercept with "on", try this
formio.emit('submitError', res);// formio.emit('submitError', res);
The button with red background will be displayed by default
To intercept the event triggered by the emit, do the code below
formio.on('submitDone', function(res) { /*your code here*/ }
Related
As we know, in mobile web-browser, if you click back button, the web-app will go to previous page, right?
But what if I want to make a certain condition which will prevent the web-app to go to previous page.
For example, if a SweetAlert2 dialog is popped-up, the back button will close the SweetAlert2 dialog.. but if there is no SweetAlert2 dialog, the back button will go to previous page..
The code I expected is like below:
export default {
mounted() {
document.addEventListener("backbutton", function(){
if(is_swal_open){
close_swal_dialog();
return false; // NOTE: i expected this should prevent from go to previous page
}
});
},
}
What you can do is warn the user:
if(is_swal_open)
{
window.onbeforeunload = function() { return "Your warning here."; };
}
or add an event listener like so:
window.addEventListener('beforeunload', function (e) {
if(is_swal_open)
{
// Cancel the event
e.preventDefault();
// Chrome requires returnValue to be set
e.returnValue = '';
}
});
I have a page that is built around a wrapper with some very defined logic. There is a Save button on the bottom of the wrapped form that looks like this:
<form>
... my page goes here...
<input id="submitBtnSaveId" type="button" onclick="submitPage('save', 'auto', event)" value="Save">
</form>
This cannot change...
Now, I'm writing some javascript into the page that gets loaded in "...my page goes here...". The code loads great and runs as expected. It does some work around the form elements and I've even injected some on-page validation. This is where I'm stuck. I'm trying to "intercept" the onclick and stop the page from calling "submitPage()" if the validation fails. I'm using prototype.js, so I've tried all variations and combinations like this:
document.observe("dom:loaded", function() {
Element.observe('submitBtnSaveId', 'click', function (e) {
console.log('Noticed a submit taking place... please make it stop!');
//validateForm(e);
Event.stop(e);
e.stopPropagation();
e.cancelBubble = true;
console.log(e);
alert('Stop the default submit!');
return false;
}, false);
});
Nothing stops the "submitPage()" from being called! The observe actually works and triggers the console message and shows the alert for a second. Then the "submitPage()" kicks in and everything goes bye-bye. I've removed the onclick attached to the button in Firebug, and my validation and alert all work as intended, so it leads me to think that the propagation isn't really being stopped for the onclick?
What am I missing?
So based on the fact that you can't change the HTML - here's an idea.
leave your current javascript as is to catch the click event - but add this to the dom:loaded event
$('submitBtnSaveId').writeAttribute('onclick',null);
this will remove the onclick attribute so hopefully the event wont be called
so your javascript will look like this
document.observe("dom:loaded", function() {
$('submitBtnSaveId').writeAttribute('onclick',null);
Element.observe('submitBtnSaveId', 'click', function (e) {
console.log('Noticed a submit taking place... please make it stop!');
//validateForm(e);
Event.stop(e);
e.stopPropagation();
e.cancelBubble = true;
console.log(e);
alert('Stop the default submit!');
return false;
submitPage('save', 'auto', e);
//run submitPage() if all is good
}, false);
});
I took the idea presented by Geek Num 88 and extended it to fully meet my need. I didn't know about the ability to overwrite the attribute, which was great! The problem continued to be that I needed to run submitPage() if all is good, and that method's parameters and call could be different per page. That ended up being trickier than just a simple call on success. Here's my final code:
document.observe("dom:loaded", function() {
var allButtons = $$('input[type=button]');
allButtons.each(function (oneButton) {
if (oneButton.value === 'Save') {
var originalSubmit = oneButton.readAttribute('onclick');
var originalMethod = getMethodName(originalSubmit);
var originalParameters = getMethodParameters(originalSubmit);
oneButton.writeAttribute('onclick', null);
Element.observe(oneButton, 'click', function (e) {
if (validateForm(e)) {
return window[originalMethod].apply(this, originalParameters || []);
}
}, false);
}
});
});
function getMethodName(theMethod) {
return theMethod.substring(0, theMethod.indexOf('('))
}
function getMethodParameters(theMethod) {
var parameterCommaDelimited = theMethod.substring(theMethod.indexOf('(') + 1, theMethod.indexOf(')'));
var parameterArray = parameterCommaDelimited.split(",");
var finalParamArray = [];
parameterArray.forEach(function(oneParam) {
finalParamArray.push(oneParam.trim().replace("'","", 'g'));
});
return finalParamArray;
}
I would like to turn a primitive event (a click) into a semantic event, like "deleteTodo"
This is described here, but not how to implement :(
I have the following code:
App.TodoView = Em.View.extend({
click: function(e) {
this.trigger("deleteTodo");
}
});
App.Router.map(function(match) {
match('/').to('index');
});
App.IndexRoute = Ember.Route.extend({
deleteTodo: function(e) {
// this code is never executed :(
}
}) ;
After I perform the 'click', I see that the TodoView click function is called, but not the deleteTodo function from the IndexRoute. Any suggestions what might go wrong here ?
CHeers
You can use this.get("controller").send("deleteTodo"). This will send a message to the controller, if the controller doesn't handle deleteTodo it will bubble to the router and be handled there.
click: function(e) {
this.get('controller').send("deleteTodo");
}
In your router you will also need to define the event:
events: {
doStuff: function(e) {
alert("Do stuff") ;
}
}
http://jsfiddle.net/9Xasr/7/
I would typically do record deletion in the controller. Seems like putting that in a router event would not be ideal.
I have buttons that trigger jQuery validation. If the validation fails, the button is faded to help draw attention away from the button to the validation messages.
$('#prev,#next').click(function (e)
{
var qform = $('form');
$.validator.unobtrusive.parse(qform);
if (qform.valid())
{
// Do stuff then submit the form
}
else
{
$('#prev').fadeTo(500, 0.6);
$('#next').fadeTo(500, 0.6);
}
That part works fine.
However, I would like to unfade the buttons once the invalid conditions have been cleared.
Is it possible to hook into jQuery Validation to get an appropriate event (without requiring the user to click a button)? How?
Update
Based on #Darin's answer, I have opened the following ticket with the jquery-validation project
https://github.com/jzaefferer/jquery-validation/issues/459
It might sound you strange but the jQuery.validate plugin doesn't have a global success handler. It does have a success handler but this one is invoked per-field basis. Take a look at the following thread which allows you to modify the plugin and add such handler. So here's how the plugin looks after the modification:
numberOfInvalids: function () {
/*
* Modification starts here...
* Nirmal R Poudyal aka nicholasnet
*/
if (this.objectLength(this.invalid) === 0) {
if (this.validTrack === false) {
if (this.settings.validHandler) {
this.settings.validHandler();
}
this.validTrack = true;
} else {
this.validTrack = false;
}
}
//End of modification
return this.objectLength(this.invalid);
},
and now it's trivial in your code to subscribe to this event:
$(function () {
$('form').data('validator').settings.validHandler = function () {
// the form is valid => do your fade ins here
};
});
By the way I see that you are calling the $.validator.unobtrusive.parse(qform); method which might overwrite the validator data attached to the form and kill the validHandler we have subscribed to. In this case after calling the .parse method you might need to reattach the validHandler as well (I haven't tested it but I feel it might be necessary).
I ran into a similar issue. If you are hesitant to change the source as I am, another option is to hook into the jQuery.fn.addClass method. jQuery Validate uses that method to add the class "valid" to the element whenever it is successfully validated.
(function () {
var originalAddClass = jQuery.fn.addClass;
jQuery.fn.addClass = function () {
var result = originalAddClass.apply(this, arguments);
if (arguments[0] == "valid") {
// Check if form is valid, and if it is fade in buttons.
// this contains the element validated.
}
return result;
};
})();
I found a much better solution, but I am not sure if it will work in your scenario because I do not now if the same options are available with the unobtrusive variant. But this is how i did it in the end with the standard variant.
$("#form").validate({
unhighlight: function (element) {
// Check if form is valid, and if it is fade in buttons.
}
});
I need to avoid the double click submitting behavior. I'm using the client validation with the unobtrusive library. I have the following code for avoiding the double clic:
jQuery.fn.preventDoubleSubmit = function () {
var alreadySubmitted = false;
return jQuery(this).submit(function () {
if (alreadySubmitted)
return false;
else {
alreadySubmitted = true;
}
});
};
jQuery('form').preventDoubleSubmit();
Unfortunately, if my form has some validable fields (for example, a required field), the code above is still being fired, hence, even if I correct any mistakes on the form, I won't be able to submit it again.
How can I fire the double click code after the validation has been succesfully done?
You can also use the JQuery One event.
I have found that I could get past most guards against double-clicks by double-clicking fast. Using the one event is the only true way to make sure the event is only fired once. I don't think this technique will work "out of the box" with an input type=submit tag. Instead, you can simply use an input type=button or JQueryUI's .button().
$("#submitButton").one("click", function(event) {
$('#theForm').submit();
});
If you need to re-wire the event on a validation error (or other circumstance), I recommend that you create a function for the event handler. The function isn't necessary in this example because all the event handler does is submit the form, but in more complicated scenarios you may want to avoid repeating yourself.
function submitClick(event) {
$('#theForm').submit();
}
$("#submitButton").one('click', function(event) {
submitClick(event);
});
// This handler will re-wire the event when the form is invalid.
$('#theForm').submit(function(event) {
if (!$(this).valid()) {
event.preventDefault();
$('#submitButton').one('click', function(event) { submitClick(event); });
}
});
You could obviously add the disabling code here if you wanted to give feedback to the user that the button doesn't work anymore. One great side-effect of using the One event is that you don't actually have to make the button disabled, you can use a style of your own.
function submitClick(event) {
$('#submitButton').addClass('disabledButton');
$('#theForm').submit();
}
$("#submitButton").one('click', function(event) {
submitClick(event);
});
// This handler will re-wire the event when the form is invalid.
$('#theForm').submit(function(event) {
if (!$(this).valid()) {
event.preventDefault();
$('#submitButton').one('click', function(event) { submitClick(event); });
$('#submitButton').removeClass('disabledButton');
}
});
JQuery One Event: http://api.jquery.com/one/
I solved it with the following code:
var tryNumber = 0;
jQuery('input[type=submit]').click(function (event) {
var self = $(this);
if (self.closest('form').valid()) {
if (tryNumber > 0) {
tryNumber++;
alert('Your form has been already submited. wait please');
return false;
}
else {
tryNumber++;
}
};
});
NOTE: You can also replace the:
return false;
line, for:
self.attr('disabled', true);
BUT, if you use the name of your submit buttons on your controller for extra logic, they will be sent as null. (you can use an additional hidden field to charge them before submitting)
that's it, hope it helps
Rodrigo
EDIT: Thanks to these posts:
jquery newbie: combine validate with hidding submit button
Why not just use:
function disableButtons() {
var form = $(this);
var btns = $("input:submit", form);
if (!form.valid()) {
// allow user to correct validation errors and re-submit
btns.removeAttr("disabled");
} else {
btns.attr("disabled", "disabled");
}
}
to disable your buttons and activate it using:
$("form").bind("submit", disableButtons);
Based on Ryan P's popular answer I created the following generic solution that also works with my ajax form.
decorate your custom submit button with the following class:
<button type="button" class="one-click-submit-button">Submit</button>
Add the following to your javascript file:
function OneClickSubmitButton() {
$('.one-click-submit-button').each(function () {
var $theButton = $(this);
var $theForm = $theButton.closest('form');
//hide the button and submit the form
function tieButtonToForm() {
$theButton.one('click', function () {
$theButton.hide();
$theForm.submit();
});
}
tieButtonToForm();
// This handler will re-wire the event when the form is invalid.
$theForm.submit(function (event) {
if (!$(this).valid()) {
$theButton.show();
event.preventDefault();
tieButtonToForm();
}
});
});
}
OneClickSubmitButton();
since this is an ajax form we want to reload the handlers if we fail server validation.
function MyForm_OnSuccess() {
if (true if your form passed validation logic) {
//do something since your form submitted successfully
} else { //validation failed on server
OneClickSubmitButton(); //reinitialize the button logic
}
}
Obviously if you don't have ajax forms you can omit the whole OneClickSubmitButton function business and run $('.one-click-submit-button').each(... directly.
I have a form that uses MVC3 unobtrusive validation, and a viewmodel with a [RemoteAttribute].
It looks to me like the form's submit event only fires after all validation has passed. I'm currently using this, and it seems to work:
<input type="submit" value="Submit the Form"
data-app-disable-on-submit="true" />
$('form').live('submit', function() {
$(this).find('input[type="submit"][data-app-disable-on-submit="true"]')
.attr('disabled', 'disabled');
})
;
I set breakpoints on both the remote attribute validation action method and the HttpPost action method. Clicking the submit button the first time hits the breakpoint on the validation action method. At this point, the button is still enabled. I can click it multiple times, and after resuming the validation method, the HttpPost is hit only once. When the HttpPost is hit, the submit button is disabled.
Update
Right you are Alex. So an updated version of the above would look like this:
$('form').on('submit', function() {
$(this).find('input[type="submit"][data-app-disable-on-submit="true"]')
.attr('disabled', 'disabled');
})
$('form').submit(function () {
$('input[type="submit"]', this).attr('disabled', 'disabled');
});
I use a different approach to this. Not wiring to the click event of the button, but to the submit event of the form. Works like a charm to prevent multiple simultaneous submits of forms.
function initFormsToPreventSimultaneousSubmits(selector) {
if (!selector) {
selector = 'form'; // No selector supplied, apply to all forms on the page
}
// Make sure all forms that conform to selector are marked as not submitting
$(selector).each(function()
{
var $form = $(this);
$form.data('submitting', false);
});
// Attach to submit event of all forms that conform to selector
$(selector).off('submit').on('submit', function (e) {
var $form = $(this);
if (!$form.valid || $form.valid()) { // Make sure to only process when the form is valid or jquery validation is not used
if ($form.data('submitting')) {
// form is already submitting. Classic case of double click on one of the submit buttons of the form. Stop the submit
e.preventDefault();
return false;
} else {
// All ok, mark the form as submitting and let the form perform the submit
$form.data('submitting', true);
return true;
}
}
});
}
On document ready i call initFormsToPreventSimultaneousSubmits() to init all forms on the page.
Only thing to remember is that when u use a ajax form post is to call the initFormsToPreventSimultaneousSubmits('#formId') on the OnComplete event of the AjaxOptions settings. Because otherwise the form will still be marked as submitting when its done. When a 'normal' form post is used this is not an issue.
Extends answers by Alex and Ryan P to accounts for situations where jQuery Validation might be missing and where multiple submit buttons exist in a single form.
oneClickSubmitButton = function () {
$('input[type=submit], button[type=submit], input[type=image]').each(function () {
var $theButton = $(this);
var $theForm = $theButton.closest('form');
//hide the button and submit the form
function tieButtonToForm() {
$theButton.one('click', function () {
$theButton.addClass('ui-state-disabled');
});
}
tieButtonToForm();
$theForm.submit(function (event) {
// Only proceed for the clicked button
if (!$theButton.hasClass("ui-state-disabled"))
return;
// If jQuery Validation is not present or the form is valid, the form is valid
if (!$theForm.valid || $theForm.valid())
return;
// Re-wire the event
$theButton.removeClass('ui-state-disabled');
event.preventDefault();
tieButtonToForm();
});
});
};
I was able to fix a similar issue with a couple of lines of code. I prefer this if you don't want to "alert" to user that they double clicked and just silently ignore the second click.
I just made a global javascript variable that I toggled when my function was executing during a critical section. This kept subsequent function calls from re-executing the same section.
var criticalSection = false;
SomeOnClickEventFired = function () {
if (!criticalSection)
{
criticalSection = true;
//Ajax Time
criticalSection = false;
}
}