JQuery validation works only on debug modus - javascript

I have an empty form and a dropdown list, where on each click, different elements will be attached to the form. I called JQuery validate() once to initialize the validator and defined the validation rules everytime the form is filled up using rules.add().
The required validation worked if I type something in the form, erase it, and click submit. But if I don't give any inputs and immediately click submit, the form don't give an error message saying the inputs are required. It worked only when I set a breakpoint in Chrome.
Did I miss something?
ASPX page
<div id="divMenuQuery">
<div id="divQueryDDL"></div>
<div id="divQueryControls">
<form id="formQuery" />
</div>
<input type="button" id="btnExecuteQuery" runat="server" value="Execute" />
</div>
JS - The example below is only for textbox, but it happens for all HTML controls (DDL, Listbox, ...)
function _init() {
$form = $("#formQuery");
_createDDL(); // creates DDL and registers event handler below
}
function _onChangeDDL() {
var selectedTheme = $(this).val;
$form.validate();
$.each(selectedTheme.Controls, function (index, control) {
_buildControl(index, control);
}
}
function _buildControl(control) {
switch (control.Type) {
case Gon.Control.textBox:
_createTextBox(control);
break;
default:
break;
}
}
function _createTextBox(control) {
var $textBox = $("<input>");
$textBox.attr({
id: control.UniqueID,
name: control.UniqueID,
value: ""
}).appendTo($form);
$textBox.rules("add", {
required: true,
messages: {
required: "This field is required"
}
});
}
function _onClickExecute() {
var numErrors = $form.validate().numberOfInvalids(); // always gives 0
var formNodes = $form.serializeArray();
if (numErrors == 0 && $form.valid()) { // .valid() always gives true
_showQueryResults(formNodes);
}
}
Here is the rendered HTML page:

Related

Implementing jQuery AJAX from within Javascript

I used a tutorial from css-tricks to help me with HTML5 Constraint Validation for my application's client-side validation. I would like to introduce an AJAX script that submits the form to prevent reloading the page (as the form is displayed in a modal pop-up that I don't want closing on submit.)
From what I have gathered online, it seems the best way to do this is to use jQuery. However, the validation script is written in regular ol' Javascript.
I'm kind of confused as to how to implement this within my validation script so that I don't need to make another http request to a separate js file (not even sure if that's an option, as I kind of need it to work seamlessly with the existing script). Do I just call jQuery inside the existing script to prevent conflicts (as shown below?) Do I need to wrap the entire script in the ready event?
Currently, I'm not sure why this isn't working. The form still submits and reloads the page, so it seems to be ignoring the Ajax submit function.
The following includes the form markup from its PHP class and the form.validate.js file used for validation and ajax:
function copyTxtVal(bf) {
if(bf.samecheck.checked == true) {
bf.contact_name_first.value = bf.cpap_sup_name_first.value;
bf.contact_name_last.value = bf.cpap_sup_name_last.value;
} else {
bf.contact_name_first.value = '';
bf.contact_name_last.value = '';
}
}
// Add the novalidate attribute when the JS loads
var forms = document.querySelectorAll('.validate');
for (var i = 0; i < forms.length; i++) {
forms[i].setAttribute('novalidate', true);
}
// Validate the field
var hasError = function (field) {
// Don't validate submits, buttons, file and reset inputs, and disabled fields
if(field.disabled || field.type === 'file' || field.type === 'reset' || field.type === 'submit' || field.type === 'button') return;
// Get Validity
var validity = field.validity;
// Get valid, return null
if(validity.valid) return;
// If field is required and empty
if (validity.valueMissing) return 'Please fill out this field.';
// If not the right type
if (validity.typeMismatch) {
if(field.type === 'email') return 'Please enter an email address.';
if(field.type === 'url') return 'Please enter a URL.';
}
// If too short
if (validity.tooShort) return 'Please lengthen this text to ' + field.getAttribute('minLength') + ' characters or more. You are currently using ' + field.value.length + ' characters.';
// If too long
if (validity.tooLong) return 'Please short this text to no more than ' + field.getAttribute('maxLength') + ' characters. You are currently using ' + field.value.length + ' characters.';
// If number input isn't a number
if (validity.badInput) return 'Please enter a number.';
// If a number value doesn't match the step interval
if (validity.stepMismatch) return 'Please select a valid value.';
// If a number field is over the max
if (validity.rangeOverflow) return 'Please select a smaller value.';
// If a number field is below the min
if (validity.rangeUnderflow) return 'Please select a larger value.';
// If pattern doesn't match
if (validity.patternMismatch) {
// If pattern info is included, return custom error
if (field.hasAttribute('title')) return field.getAttribute('title');
// Otherwise, generic error
return 'Please match the requested format.';
}
// If all else fails, return a generic catchall error
return 'The value you entered for this field is invalid.';
};
var showError = function(field, error){
// Add error class to field
field.classList.add('error');
// Get field id or name
var id = field.id || field.name;
if (!id) return;
// Check if error message field already exists
// If not, create one
var message = field.form.querySelector('.error-message#error-for-' + id );
if (!message) {
message = document.createElement('div');
message.className = 'error-message';
message.id = 'error-for-' + id;
field.parentNode.insertBefore( message, field.nextSibling );
}
// Add ARIA role to the field
field.setAttribute('aria-describedby', 'error-for-' + id);
// Update error message
message.innerHTML = error;
// Show error message
message.style.display = 'block';
message.style.visibility = 'visible';
}
var removeError = function(field) {
// Remove the error message
// Remove error class to field
field.classList.remove('error');
// Remove ARIA role from the field
field.removeAttribute('aria-describedby');
// Get field id or name
var id = field.id || field.name;
if (!id) return;
// Check if an error message is in the DOM
var message = field.form.querySelector('.error-message#error-for-' + id + '');
if (!message) return;
// If so, hide it
message.innerHTML = '';
message.style.display = 'none';
message.style.visibility = 'hidden';
};
//Listen to all blur events
document.addEventListener('blur', function (event) {
// Only run if field is in a form to be validated by our custom script
if (!event.target.form.classList.contains('validate')) return;
// Validate field
var error = hasError(event.target);
// If there's an error, show it
if(error){
showError(event.target, error);
return;
}
//Otherwise, remove any existing error msg
removeError(event.target);
}, true);
// Check all fields on submit
document.addEventListener('submit', function (event) {
// Only run on forms flagged for validation
if (!event.target.classList.contains('validate')) return;
// Get all of the form elements
var fields = event.target.elements;
// Validate each field
// Store the first field with an error to a variable so we can bring it into focus later
var error, hasErrors;
for (var i = 0; i < fields.length; i++) {
error = hasError(fields[i]);
if (error) {
showError(fields[i], error);
if (!hasErrors) {
hasErrors = fields[i];
}
}
}
// If there are errors, don't submit form and focus on first element with error
if (hasErrors) {
event.preventDefault();
hasErrors.focus();
}
// Call self invoking jQuery function to handle form submit by Ajax if validation passes
else {
(function($){
var form = $('#cpapsupform');
var formMessages = $('#cpap-form-messages');
// Is this line below necessary if I've done this in the normal js above?
$(form).submit(function(event){
event.preventDefault();
// Serialize Form Data
var formData = $(form).serialize();
//Submit the form via AJAX
$.ajax({
type: 'POST',
url: $(form).attr('action'),
data: formData
})
.done(function(response) {
// Make sure that the formMessages div has the 'success' class.
$(formMessages).removeClass('error');
$(formMessages).addClass('success');
// Set the message text.
$(formMessages).text(response);
// Clear the form.
$('#cpap_sup_name_first').val('');
$('#cpap_sup_name_last').val('');
$('#contact_name_first').val('');
$('#contact_name_last').val('');
$('#cpap_contact_email').val('');
$('#cpap_contact_phone').val('');
$('#cpap_patient_dob').val('');
$('#cpap_patient_zip').val('');
})
.fail(function(data) {
// Make sure that the formMessages div has the 'error' class.
$(formMessages).removeClass('success');
$(formMessages).addClass('error');
// Set the message text.
if (data.responseText !== '') {
$(formMessages).text(data.responseText);
} else {
$(formMessages).text('An error occured and your message could not be sent.');
}
});
});
})(jQuery);
}
}, false);
Here is the form markup (excerpted from the php form class I am using):
<?php
<div id="cpap-form-area">
<div id="cpap-form-messages"></div>
<div class="cpap-form-greet">
<p>Some text goes here.</p>
</div>
<form method="POST" action="" id="cpapsupform" class="validate" enctype="multipart/form-data" >
<fieldset>
<legend>Patient Name</legend>
<div class="p-firstname">
<label for="cpap_sup_name_first">First Name:</label>
<input type="text" size="50" name="cpap_sup_name_first" id="cpap_sup_name_first" value="<?php echo $display['cpap_sup_name_first']; ?>" required />
</div>
<div class="p-lastname">
<label for="cpap_sup_name_last">Last Name:</label>
<input type="text" size="50" name="cpap_sup_name_last" id="cpap_sup_name_last" value="<?php echo $display['cpap_sup_name_last']; ?>" required />
</div>
</fieldset>
<fieldset>
<legend>Point of Contact</legend>
<div class="samename">
<div class="cpap_input_alt">
<input id="samecheck" type="checkbox" name="samecheck" onchange="copyTxtVal(this.form);">
</div>
<label for="samecheck">Use same as above</label>
</div>
<div class="c-firstname">
<label for="contact_name_first">First Name:</label>
<input type="text" size="50" name="contact_name_first" id="contact_name_first" value="<?php echo $display['contact_name_first']; ?>" required />
</div>
<div class="c-lastname">
<label for="contact_name_last">Last Name:</label>
<input type="text" size="50" name="contact_name_last" id="contact_name_last" value="<?php echo $display['contact_name_last']; ?>" required />
</div>
</fieldset>
<fieldset>
<legend>Contact Details</legend>
<div class="cpap-email-contact">
<label for="cpap_contact_email">Email:</label>
<input type="email" name="cpap_contact_email" id="cpap_contact_email" value="<?php echo $display['cpap_contact_email']; ?>" title="The domain portion of the email after '#' is invalid." pattern="^([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22))*\x40([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d))*(\.\w{2,})+$" required />
</div>
<div class="cpap-tel-contact">
<label for="cpap_contact_phone">Phone:<br /><span class="tiny-txt">(10 digits; no spaces)</span></label>
<input type="text" maxlength="10" name="cpap_contact_phone" id="cpap_contact_phone" value="<?php echo $display['cpap_contact_phone']; ?>" pattern="\d{10}" required />
</div>
</fieldset>
<fieldset>
<legend>Patient Date of Birth</legend>
<div class="cpap-dob">
<label for="cpap_patient_dob">Birthdate: <br /><span class="tiny-txt">(MM/DD/YYYY)</span></label>
<input type="text" name="cpap_patient_dob" id="cpap_patient_dob" value="<?php echo $display['cpap_patient_dob']; ?>" title="Your date looks incorrect, or it doesn't match the required format." max-length="10" pattern="((0[1-9])|(1[0-2]))/(([0-2]\d)|([3][01]))/((19|20)\d{2})" required ></input>
</div>
</fieldset>
<fieldset>
<legend>Address Info</legend>
<div class="cpap-zip">
<label for="cpap_patient_zip">Patient Zipcode:<br /><span class="tiny-txt">(first 5 digits only)</span></label>
<input type="text" maxlength="5" name="cpap_patient_zip" id="cpap_patient_zip" value="<?php echo $display['cpap_patient_zip']; ?>" required ></input>
</div>
</fieldset>
<button type="submit" id="cpapAjaxButton" name="cpapAjaxButton">Submit Request</button>
<p class="form-msg">All fields must be completed</p>
<div class="clearfix"></div>
<?php wp_nonce_field('submit_cpap_form','nonce_field_for_submit_cpap_form'); ?>
</form>
</div>
First, you do have a syntax error in that you are missing the opening curly brace of your else branch right here:
// Call self invoking jQuery function to handle form submit by Ajax if validation passes
else (function($){
It should be:
// Call self invoking jQuery function to handle form submit by Ajax if validation passes
else { (function($){
And, to avoid these kinds of errors, good indentation and formatting of code goes a long way, so really, this would be the best way to write it:
// Call self invoking jQuery function to handle form submit by Ajax if validation passes
else {
(function($) {
Now, to you main point. As long as you have referenced the JQuery library prior to your code needing to use it, you just go ahead and use JQuery when and where you need to. If you need some page initialization work done, then yes, a "document ready" function should be passed into the JQuery object. But, apart from that, you can leverage JQuery whenever you need to so the self-invoking function you have inside of your else branch is redundant - - if code execution enters that branch, you don't invoke JQuery again, you just use it.
Also, you start off with:
document.addEventListener('submit', function (event) {
But, the document object doesn't have a submit event. The event listener should be set up on the form element that is going to be submitted.
You also have some unnecessary variables and in a couple of cases, you set your variables equal to JQuery objects, but then passed those objects into the JQuery object again later as if they were regular DOM objects.
Here is your cleaned up code. Check the comments carefully for what changes were made and why. Also, this is the best we can do with answers since you didn't provide the hasError and showError functions and your HTML as well.
// The document object doesn't get submitted, the form does.
// Also this sytax finds every form that has the "validate" class,
// so there is no need to test for that in the callback function
$("form.validate").on('submit', function (event) {
// Get all of the form elements
var fields = event.target.elements;
// Always initialize your variables. Set them to null if you don't know the value to use yet
// Also, the "error" and "hasError" variables are not needed. You'll see why in a couple of lines down.
var hasErrors = null;
for (var i = 0; i < fields.length; i++) {
// I'm assuming you have a working "hasError" function that returns a boolean
// So, just take that return value and make that the basis for the if condition -- no
// need to store it just to test it on the next line.
if (hasError(fields[i])) {
// I'm assuming you have a working "showError" function. If we've entered into this
// branch of the code, we know that "hasError" returned true, so we can just pass that
// directly into the "showError" function instead of the "error" variable that we've
// now gotten rid of.
showError(fields[i], true);
// No need to test here. There is an error.
hasErrors = fields[i];
}
}
// If there are errors, don't submit form and focus on first element with error
if (hasErrors) {
event.preventDefault();
hasErrors.focus();
} else {
// You don't need a self-invoking function here. Just write the code that should execute
// It is a common convention to name variables that store references to JQuery objects
// with a leading $ to distinguish them as such and not regular DOM objects
var $form = $('#cpapsupform');
var $formMessages = $('#cpap-form-messages');
// Submit the form via AJAX
$.ajax({
type: 'POST',
url: $form.attr('action'), // $form is already a JQuery object, don't pass it to JQuery again
data: $form.serialize() // <-- You had semi-colon here, which you shouldn't have
}).done(function(response) {
// $formMessages is already a JQuery object, don't pass it to JQuery again
$formMessages.removeClass('error');
$formMessages.addClass('success');
// Set the message text.
$formMessages.text(response);
// Just use the DOM form.reset() method here instead of resetting each form field
$form[0].reset();
}).fail(function(data) {
// Make sure that the formMessages div has the 'error' class.
$formMessages.removeClass('success');
$formMessages.addClass('error');
// Set the message text.
if (data.responseText !== '') {
$formMessages.text(data.responseText);
} else {
$formMessages.text('An error occured and your message could not be sent.');
}
});
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="#" method="GET" class="validate">
<input type="text" id="name">
<input type="submit">
</form>
<form action="#" method="GET">
<input type="text" id="name">
<input type="submit">
</form>
jQuery IS Javascript, so of course you can use them together. I think your problem might lie in you not properly bracketing your else statement:
else { (function($){ // was missing brace after 'else'
var form = $('#cpapsupform');
var formMessages = $('#cpap-form-messages');
....
})(jQuery);
}//closing else brace

Call Knockout Validation Extender on Button Click

I've been reading many questions that ask how to call a knockout validation extender on a button click event. But all the answers that come close to answering the question, involve workarounds using the knockout-validate library. I'm not using the knockout-validate library. All I want to do is validate an input field on a button click event using the validation rules defined in a knockout extender.
For simplicity I'm going to use the required extender from the knockout documentation and apply it to a simple use case. This use case takes an input and on a button click event does something with the value the user entered. Or updates the view to show the validation message if no value was entered.
Knockout Code:
ko.extenders.required = function (target, overrideMessage) {
target.hasError = ko.observable();
target.validationMessage = ko.observable();
function validate(value) {
target.hasError(value ? false : true);
target.validationMessage(value ? "" : overrideMessage || 'Value required');
}
return target;
};
function MyViewModel() {
self = this;
self.userInput = ko.observable().extend({ required: 'Please enter a value' });
/**
* Event handler for the button click event
*/
self.processInput = function () {
//Validate input field
//How to call the validate function in the required extender?
//If passes validation, do something with the input value
doSomething(self.userInput());
};
}
Markup:
<input type="text" data-bind="value: userInput, valueUpdate: 'afterkeydown'" />
<span data-bind="visible: userInput .hasError, text: userInput .validationMessage" class="text-red"></span>
<button data-bind="click: processInput ">Do Something</button>
How can I trigger the validation on the button click event and show the validation message if it doesn't pass validation?
I believe you were looking at the example here - http://knockoutjs.com/documentation/extenders.html
You can not call validate directly, but the subscribe watches the value and runs the validate function on change and updates an observable you can check - hasError.
ko.extenders.required = function (target, overrideMessage) {
target.hasError = ko.observable();
target.validationMessage = ko.observable();
function validate(value) {
target.hasError(value ? false : true);
target.validationMessage(value ? "" : overrideMessage || 'Value required');
}
//initial validation
validate(target());
//validate whenever the value changes
target.subscribe(validate);
//return the original observable
return target;
};
function MyViewModel() {
self = this;
self.userInput = ko.observable().extend({ required: 'Please enter a value' });
/**
* Event handler for the button click event
*/
self.processInput = function () {
if(self.userInput.hasError()){
console.log('has error');
}else{
console.log('no error');
}
};
}
// Activates knockout.js
ko.applyBindings(new MyViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="text" data-bind="value: userInput, valueUpdate: 'afterkeydown'" />
<span data-bind="visible: userInput .hasError, text: userInput .validationMessage" class="text-red"></span>
<button data-bind="click: processInput ">Do Something</button>

emberjs input checkValidity and setCustomValidity

Is there a way to use checkValidity() setCustomValidity() within ember? For example, in my controller upon submission I have:
var inpObj = this.get('name');
if (inpObj.checkValidity() == false) {
alert('ok');
}
and of course this is my handlebar code:
{{input id="name" type="text" value=name placeholder="Your Name" required="true"}}
Upon submission of this, I get this error message:
inpObj.checkValidity is not a function
You would need to get HTML5 element instead of string to call checkValidity function.
var inpObj = this.get('name'); // this is only a string
You can use jQuery instead:
var inpObj = Ember.$('#name')[0];
if (inpObj.checkValidity() == false) {
alert('ok');
}
Working demo.
If you want to avoid jQuery, you could set an action on your submit button that runs the valid check for you.
<button {{action "submitForm"}}>Your Button</button>
Then have an action in your contoller:
actions: {
submitForm() {
var inpObj = this.get('name');
if(!inpObj.checkValidity()) {
// error handling
alert('ok');
} else {
// save your data, or whatever you need to do
this.transitionTo('some.route');
}
}
}

How to pass a callback function to a compiled Jade template without declaring it globally in javascript

I have created a Backgrid table to manage users. One of the functions of that table is to allow paswords to be changed by an administrator. This is achieved by adding a button cell column to the backgrid table that launches a modal change password dialog. On entering the passwords and clicking change, the new password is passed back to the backgrid cell and inserted to the backbone model in the callback.
The problem is passing the callback, because the change password dialog is a compiled client side Jade template, so I can't pass a function in the options when the html is rendered, I can only pass a function name.
Here is what I have so far (showing only the Jade and the Backgrid PasswordCell definition).
The client side Jade template:
#user-passwd-dialog.modal
.modal-dialog
.modal-content
.modal-header.bg-warning
button.close(type="button" data-dismiss="modal" aria-label="Close")
span(aria-hidden="true") ×
h4.modal-title
span.glyphicon.glyphicon-log-in
span Set User Password
.modal-body
if message.length > 0
// show any messages that come back with authentication
.alert.alert-info #{message}
// LOGIN FORM
form
.form-group
label(for="user-password") Password
input.form-control#user-password(type="password" placeholder="New Password")
.form-group
label(for="user-confirm") Confirm Password
input.form-control#user-confirm(type="password" disabled="disabled" placeholder="Confirm Password")
.modal-footer
button.btn.btn-warning.btn-lg#user-change-password(type="button" disabled="disabled") Change Password
button.btn.btn-warning.btn-lg(type="button" data-dismiss='modal') Cancel
script(type="text/javascript").
function checkMatch() {
var password = $("#user-password").val();
var confirmPassword = $("#user-confirm").val();
if (password !== confirmPassword) {
$("#user-confirm").removeClass("alert alert-success").addClass("alert alert-danger");
$("#user-change-password").prop("disabled", true);
return false;
} else {
$("#user-confirm").removeClass("alert alert-danger").addClass("alert alert-success");
$("#user-change-password").prop("disabled", false);
return true;
}
}
$("#user-password").keyup(function() {
var password = $("#user-password").val();
if (password.length >= #{ minLen }) {
$("#user-confirm").prop("disabled", false);
checkMatch();
} else {
$("#user-confirm").prop("disabled", true);
}
});
$("#user-confirm").keyup(function() {
var password = $("#user-password").val();
if (password.length >= #{ minLen }) {
checkMatch();
}
});
$("#user-change-password").click(function() {
var password = $("#user-password").val();
#{result}(password);
$('#user-passwd-dialog').modal('hide');
});
The Backgrid cell is defined as (the compiled Jade template is Templates.set_password(opts)):
var PasswordCell = Backgrid.Cell.extend({
className: "button-cell",
template: function () {
return '<button class="btn btn-sm btn-warning"><span class="glyphicon glyphicon-lock"></span></button>';
},
events: {
"click": "setPassword"
},
setPassword: function (e) {
e.preventDefault();
// XXX binding to global variable so modal can set password
// must be more elegant way to do this
mycallbackwiththelongname = (function(password) {
this.model.set({ password : password});
}).bind(this);
var opts = {
message:"The password must be at least 8 characters long",
minLen: 8,
result: "mycallbackwiththelongname"
};
$("#dialog-wrapper").html(Templates.set_password(opts));
$("#user-passwd-dialog").modal({ keyboard: true });
},
render: function () {
this.$el.html(this.template());
this.delegateEvents();
return this;
}
});
The question is in the code: Is there a more elegant way to pass the callback such that a global function is not needed. A local function would be preferable, but I am not sure how to specify the name.
I have a simplified jsfiddle working using the global function.
I figured out a way to use a function local to the PasswordCell 'click' handler by passing it using the jQuery data API. I attach the callback function to the parent element and then pass the name of the parent element to the function that renders the Jade template.
In the PasswordCell change setPasswd to:
setPassword: function (e) {
e.preventDefault();
var passwordResult = (function(password) {
this.model.set({ password : password});
}).bind(this);
var opts = {
name: "change-password-modal",
message:"The password must be at least 8 characters long",
minLen: 8,
parent: "dialog-wrapper"
};
$("#dialog-wrapper").html(Templates.set_password(opts));
$("#dialog-wrapper").data("onChange", passwordResult);
$("#user-passwd-dialog").modal({ keyboard: true });
},
In the Jade template change the button click event handler:
$("#user-change-password").click(function() {
var password = $("#user-password").val();
$("##{ parent }").data("onChange")(password);
$('#user-passwd-dialog').modal('hide');
});
The jsfiddle has been updated.

I have to press submit button twice in IE using jquery framework to submit form

I have a strange behaviour in IE browser.
I have simple form:
<form name="test" id="test" action="some_url_here" method="post">
<input type="text" name="url" id="url" class="required" />
<input type="text" name="page" id="page" class="required" />
...
<input type="submit" name="submit" value="Submit" />
</form>
and in JS:
var result = true;
$("#test").on("submit", function(){
$(".required").removeClass("error");
$.each($("input.required"), function(k, v) {
if($(this).val() === '') {
$(this).addClass("error");
result = false;
return false;
}
});
if(result) {
if(!IsValidUrl($("input[name='url']").val()){
$("input[name='url']").addClass("error");
return false;
}
} else {
return false;
}
});
Let's assume that I filled all fields correctly.
In Chrome & Firefox, when I press on submit button then works fine, just once time.
In IE (all versions) I have to press two times on the submit form to execute/sumbit the form.
Why ?
I tried also to put after IsValidUrl condition:
$(this).submit();
But no success.
You have two options here. On both you need to stop the submit event and validate the form.
One is to go through all the fields in the form, add the class error to the invalid ones (if there's any), set the variable result and return (or submit if everything is alright).
The other is to stop the test at the first invalid field found, not using the variable result, and return (or submit if everything is alright).
JS
$(function () {
$("#test").on("submit", function (e) {
// Stop the submit, because you need to validate the form before proceeding.
e.preventDefault();
// Check the comments below to decide for the use of the variable.
var result = true;
$(".required").removeClass("error");
$.each($("input.required"), function (k, v) {
// Test for empty fields or, if it's the URL, check whether is valid.
if ($(this).val() === "" || ($(this).attr("name") == "url" && !IsValidUrl($(this).val())) {
// Add class error to the invalid fields.
$(this).addClass("error");
// At this point, you could just return false stopping the loop,
// or keep going to make sure all the invalid fields will get the
// class error. In this case, you can still use the variable result.
result = false;
// Keep going, so, no return.
// return false;
}
});
// If you decided to carry on through all the fields, and don't return
// false at the first error, test for the result value.
// As this is the case...
if (!result) return false;
else $(this).submit();
// If you didn't return previously...
// $(this).submit();
});
});

Categories

Resources