trigger unobtrusive validation but prevent submit on mvc4 form - javascript

I have a form, this form has some values that are required, so in my viewmodel I have some things like:
[Required(ErrorMessageResourceType = typeof(Res_Errors), ErrorMessageResourceName = "errorPacienteNoSeleccionado")]
public int? scheduledIdPersonaSeleccionada { get; set; }
as well as a submit button, but I don't want to submit the form to the server, I only need to execute a jquery function if my validation passes.
The validation is working but I don't know how to prevent the form from posting and instead call my function.

if you only want to execute javascript on form submit (and not actually send the information) have a look at #Ajax.BeginForm:
#using (Ajax.BeginForm(new AjaxOptions { OnBegin = "MyFunction" }))
{
#Html.EditorFor(x => x.scheduledIdPersonaSeleccionado)
<input type="submit" value="Presentar" />
}
Alternatively you can hook in to the submit event and do it yourself:
$('form').submit(function(){
if ($(this).valid()) { // validation passed
// cal your jquery function here
}
});

Change your submit button to button type. Validation will call, but submit won't
<form>
#Html.EditorFor(x => x.scheduledIdPersonaSeleccionado)
#Html.ValidationMessageFor(x=>x.scheduledIdPersonaSeleccionado)
<input type="button" value="Presentar" onclick="DoSomething();" />
</form>

I solved it by hacking through jQuery Validate default options. jQuery Validate is used under the hood by unobtrusive validation.
If you have only one form to validate on the page, you can define globally a submit handler which will execute only when a valid form is submitted:
$.validator.setDefaults({
submitHandler: function (form, e) {
// your code
}
});
It has to be defined before the unobtrusive initialization, which occurs on ready. Or you will have to re-parse the form with $.validator.unobtrusive.parse(selectorOfYourForm).
In my case, having many forms with different needs, I have used something like this:
let submitHandlers = [];
$.validator.setDefaults({
submitHandler: function (form, e) {
let result = true;
$.each(submitHandlers, function (i, submitHandler) {
result = submitHandler(form, e) && result;
});
return result;
}
});
function addUnobstrusiveValidationSubmitHandler(submitHandler) {
if (typeof submitHandler !== 'function') {
throw 'submitHandler must be a function';
}
submitHandlers.push(submitHandler);
}
I leave to each submitHandler the responsibility of working only on forms it has to handle. The submit handler should check the form, and just return true; without doing anything else if it is not a form it should handle. So adding a bad submitHandler acting on unexpected forms will mess other forms or the whole page.
It would be better if we could define the submitHandler in the parse call instead, but currently this call does not take an options object.
(There is also some options which can be defined globally by assigning an object to $validator.unobtrusive.options, but I do not find much documentation about this beyond errorClass and errorElement options, and it does not seem to have an option for specifying a submitHandler. As far as I can see from the source, we could only define the following additional options, matching the jQuery validate ones: errorPlacement, invalidHandler and success.)

Related

Calling a custom method for form validation at runtime

I have a function called generate_form which uses jQuery to create a form and insert it into the page. Several other functions call this general one to create their form, and it in turn returns the form.
In order to do validation, i want the caller to be able to provide their own validation function as the specific use case has non-standard constraints (such as having to issue ajax calls to check/verify things). The issue i'm running into, is i'm not sure how to get the custom validation function into the submit event of the form.
Very simplified and truncated code:
function user_test() {
$('#formcontainer').append(generate_form(
{
name:'test',
id:'user_test_form',
fields:
[
{name:'username',type:'text',id:'username'}
],
validation:function() { return $('#username').length > 0; }
})
);
}
function generate_form(data) {
var form=$('<form>',{id:data['id']});
//SNIP: add fields to form
$(form).submit(function(event) {
event.preventDefault();
//does not work, because data is undefined in this scope
if ( !data['validation']() ) {
//SNIP: validation failed notice
return false;
}
//SNIP: post form
});
return form;
}
Several ways around this. One would be to bind the submission callback to the context of data, so:
$(form).on('submit', function(event) {
event.preventDefault();
if (this.validation && !this.validation()) return false;
}.bind(data));
Another would be to pass data as event data. This is done via the third param of .on():
$(form).on('submit', null, data, function(event) {//...
The original data is then accessible in the callback via event.data.
Also bear in mind you were assuming a validation callback was passed before calling it which, if there isn't one, will error.

SYMFONY FORM isClicked() issue (depending Browser) when mixed with JavaScript - JQuery: event.preventDefault() and event.target.submit()

The goal:
I want on a Symfony FORM to have two submit buttons. 1st one would be used to validate the form, the 2nd submit button would be used to get away from the form.
By default the fields of the form use the required check before submitting, which means that prior to use the 2nd Submit, the required attributes need to be turned off on DOM <input>. I do that by using some JQuery, event.preventDefault(), I turn off the required on each <input> and then do an event.target.submit().
Then on my Symfony side I expect to catch the button that had been clicked by using the $form->has([button name])->isClicked() function.
The issue:
I have noticed that depending on the browser, the $form->has([button name])->isClicked() doesn't work if some JavaScript with event.preventDefault() and event.target.submit() had been used.
On chrome (Version 51.0.2704.103 m) I get (isClicked = 1 or true):
On firefox (Version 47.0) or Microsoft EDGE 25.* I get (isClicked = false):
The code:
The full code is at the following github.
Emphasis on the code:
In /src/AppBundle/Form/FormType.php you'll find, the code that manages the JavaScript to hold on the Submit, turnoff the required and resume the Submit:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('field1',EmailType::class, array('label'=>'Form Field 1'))
->add('submit',SubmitType::class,array('label'=>'Submit Form'))
->add('get_away_from_form',SubmitType::class,array(
'label'=>'Get away from form',
'attr'=>array(
'onclick'=>'{
//IF THE USER CLICK THE NOT_SUBMIT BUTTON THE REQUIRED FIELD ARE DISABLED BEFORE THE SUBMIT HAPPENS
// Here is the part where are done (see GITHUB code for details):
////`event.preventDefault()`,
//// turn off the `required` on each `<input>`
//// and then do an `event.target.submit()`.
}'
)
));
}
In /src/AppBundle/Controller/DefaultController.php you'll find, the check on $form->get('get_away_from_form')->isClicked():
if($form->isSubmitted() && $form->has('get_away_from_form')){
if($form->get('get_away_from_form')->isClicked() == 1){
$isClicked = 'It works as expected: $form->get(get_away_from_form)->isClicked() = '.$form->get('get_away_from_form')->isClicked();
} else {
$isClicked = 'It DOESN\'T work as expected: $form->get(get_away_from_form)->isClicked() = '.$form->get('get_away_from_form')->isClicked();
}
}
Anyone has an idea?
Why are you using a submit button to get away from the form, instead of just using a link to another page ? It would avoid the need to bypass form validation
In such case one needs to use event.stopPropagation() instead of event.preventDefault().
And there is no need for the event.target.submit().
Now, my JS function associated to the onclick looks like this:
'onclick'=>'{
//IF THE USER CLICK THE NOT_SUBMIT BUTTON THE REQUIRED FIELD ARE DISABLED BEFORE THE SUBMIT HAPPENS
e= \'form\';
$(e).submit(
function(event){
event.stopPropagation();
}
);
function disableReq(e){
var disableReqDef = $.Deferred();
var disableReqDefProm = disableReqDef.promise();
requiredFields = $(e).find(\'[required="required"]\');
requiredFields.each(function(){
$(this).attr(\'required\',false);
});
disableReqDef.resolve();
return disableReqDefProm;
}
var dr = disableReq(e);
$.when(
e,
dr,
undefined
).done(function(e){
$(e).submit(function(event){});
});
}'
Why not use code like the following:
if ( $form->get('get_away_from_form')->isClicked() ){
return $this->redirectToRoute('detourRoute');
}
if ($form->isSubmitted() && $form->isValid()) {
...
Or is it that you MUST use javascript and/or JQuery in your code. My suggestion is simpler... This is only just a suggestion.

input validation vs. required to submit on multi-page forms

i have a multi-page form that i am trying to validate using jquery validate. the user has essentially 4 options: next, prev, save, submit.
save, next, and prev all save the current page to the form as a whole; submit is the same as save, but fires some additional workflow-related functions then heads off to another part of the site.
i need to validate the user input at all times. the jquery validate is working great. but... i need to have some fields set as required. because the form is saved at each step, the input needs to always be valid, but i don't need the required validation until the very end (on submit).
the form is building a dynamic list of validations specific to the page it is on, like:
$(document).ready(function() {
$("#ctl01").validate({ onsubmit: false });
$("#_Qn_0e868ebe").rules("add", { maxlength: 200 });
$("#_Qn_d69e75a4").rules("add", { number: true });
$("#_Qn_adffbdec").rules("add", { maxlength: 200 });
$("#_Qn_adffbdec").rules("add", { digits: true });
});
so now, for required fields, i've added a .isrequired class to them, and i've decoupled the <asp:linkbutton>s to fire this client script:
function FormIsValid(sender, ishardsubmit) {
var form = $("#ctl01");
form.validate();
if (form.valid()) {
//if (ishardsubmit) {
// if (!IsRequiredValid()) { return false; }
//}
__doPostBack(sender, '');
}
return;
}
this part (the input validation part) is working great so far. the part i commented out is the part that is working not so great. it fires this function, in which i was trying to dynamically add required validators and re-evaluate the form. i can see it hit the .each loop for each of my required fields, but it doesn't seem to be working since it passes true back, even when required fields are empty.
function IsRequiredValid() {
var $requiredgroup = $(".isrequired");
$requiredgroup.each(function (i, item) {
$(item).rules("add", { required: true });
});
form.validate();
return form.valid();
}
i toyed with the idea of dropping the .net required field validators in to do this part, but i want to, if possible, stick with a single solution. especially since this feels so close to working.
thoughts? help? thanks!
Your jQuery .each() method is constructed improperly.
You want to target the whole object in your iteration, not key/value pairs. So remove i, item from the function arguments and use $(this) as the target selector.
function IsRequiredValid() {
var $requiredgroup = $(".isrequired");
$requiredgroup.each(function() {
$(this).rules("add", { required: true });
});
// form.validate(); // remove this line -> 100% superfluous
return form.valid();
}
Regarding your form.validate() line in both functions: You cannot call .validate() more than once on the page. It's only meant to be called once to initialize the plugin on your form.
Calling it subsequent times will have no effect. Otherwise, we wouldn't need to use the .rules() method as we would simply call .validate() any time we need to change rules. However, this is definitely not the case.
Add a class to your required fields called something like: "SubmitRequired"
Implement two functions as follows:
function SaveClick(){
//ignore SubmitRequired on save (and any disabled fields)
$("form").validate({ ignore: ".SubmitRequired, [disabled]" });
if $("form").valid()
{
do something;
}
}
function SubmitClick(){
//ignore only disabled fields (if any))
$("form").validate({ ignore: "[disabled]" });
if $("form").valid()
{
do something;
}
}

jQuery nested phone number validation

Does anyone know how to use the jQuery validation plug-in while looping through inputs? The only way I know how to make the validation plug-in work is through a submit request. However, I am working on a multi-part form that validates on each step of the form and simply highlights required fields as the user moves through. I would like to add validation to this process as well, just not sure how to do it. Ideally, I'd like to validate more than just phone numbers, maybe email format and reg exp as well. Here the code I'm currently using:
function validateStep(step) {
if(step == fieldsetCount) return;
var error = 1;
var hasError = false;
$('#formElem').children(':nth-child('+ parseInt(step) +')').find(':input:not(button)').each(function(){
var $this = $(this);
var valueLength = jQuery.trim($this.val()).length;
if(valueLength == ''){
if($(this).hasClass('req')) {
hasError = true;
$this.addClass('hasError');
}
else
$this.removeClass('hasError');
} else {
$this.removeClass('hasError');
}
});
}
Any ideas?
The code in your question is not making a whole lot of sense to me. If you want to use the jQuery Validation plugin, then validation is handled automatically, you do not need to manually loop through any inputs.
As far as multi-step forms, there are many possible approaches. I prefer to use an individual form element for each step. Then I use the .valid() method to test the section before moving to the next. (Don't forget to first initialize the plugin; call .validate(), on all forms on DOM ready.)
Then on the last section, I use .serialize() on each form and concatenate them into a data query string to be submitted.
Something like this...
$(document).ready(function() {
$('#form1').validate({ // initialize form 1
// rules
});
$('#gotoStep2').on('click', function() { // go to step 2
if ($('#form1').valid()) {
// code to reveal step 2 and hide step 1
}
});
$('#form2').validate({ // initialize form 2
// rules
});
$('#gotoStep3').on('click', function() { // go to step 3
if ($('#form2').valid()) {
// code to reveal step 3 and hide step 2
}
});
$('#form3').validate({ initialize form 3
// rules,
submitHandler: function (form) {
// serialize and join data for all forms
var data = $('#form1').serialize() + '&' + $('#form2').serialize() + '&' + $(form).serialize()
// ajax submit
return false; // block regular form submit action
}
});
// there is no third click handler since the plugin takes care of this
// with the built-in submitHandler callback function on the last form.
});
Important to remember that my click handlers above are not using type="submit" buttons. These are regular buttons, either outside of the form tags or type="button".
Only the button on the very last form is a regular type="submit" button. That is because I am leveraging the plugin's built-in submitHandler callback function on only the very last form.
"Proof of Concept" DEMO: http://jsfiddle.net/j8vUt/
See this for reference: https://stackoverflow.com/a/19546698/594235

ASP.NET Form validation - success event in JavaScript?

I would like to subscribe to whatever event is fired when my ASP.NET form is validated successfully.
Here is the scenario: On the click of a button on a payment form, I want to show a message 'processing,' however I only want to show this button when the for is validated succesfully.
I am using native ASP.NET form validation.
In a round-about way, you can if you override the Page_ClientValidate method as in:
var fn = Page_ClientValidate;
Page_ClientValidate = function(..) {
var result = fn(..);
if (result == true) {
//run code for success
}
}
I don't know why this was demoted but this approach is great because it works from all validation scenarios for customization (from buttons, WebForms_DoPostBackWithOptions client method, etc.).
HTH.
I don't think that the built in validators expose any such events. You could always use the CustomValidator and provide a OnClientValidate method that will combine the validation you're looking for as well as the UI changes you desire.
Call the following Javascript function whenever you want and pass the validation group name of your form to it..
function ValidateForm(ValidationGroupName)
{
var validated=Page_ClientValidate(ValidationGroupName);
if(validated)
{
//do the logic here
return true;
}
else
{
return false;
}
}
Hope this will help you....
I don't think it's going to be easy to do it your way but what you can do is the following:
<asp:Button onclientclick="if (Page_IsValid) return true; else {alert('Not Valid'); return false;}"/>
This will basically throw an error is validation is incorrect, otherwise it will continue.

Categories