Jquery validator - form being saved with error

Go To StackoverFlow.com

0

I have a form with jquery validation. I have some custom rules, but they all check out and work fine on other forms. In fact, it works just fine on THIS form except for one specific situation. We have a text input for a URL. We wrote a regex to disallow script tags. And it works fine.

If you fill out the form with errors and submit it, you have error messages. As expected. But this URL field... If you entered a valid URL before failure and then change it to a script tag and click "save" the error message immediately appears but then the form submits anyway. If you tab away from the field first, you see the error message. But clicking "save" still saves the form.

I've tried using a page load function to disable the form action and to replace the action with a check if the form is valid. If you leave the form blank and click save, you get errors. If you fill it out, you get nothing. Clicking save does nothing at all.

Here is my form tag. The fields don't really matter. The issue here is that the form is failing validation but saving anyway:

<form id="frmCreateNewAd" action="/some/path" method="post" enctype="multipart/form-data">
  <input class="btnSave" type="submit" value="Save" />
</form>

Here is my attempt to change the submit action to disable the default action until it is clicked when the form passes validation:

//bind custom form action
$('#frmCreateNewAd').bind("submit", function(e){
  //disable default action
  e.preventDefault();
  //remove previous validation data
  $('#frmCreateNewAd').removeData("previousValue");
  //check if form is valid
  if ($('#frmCreateNewAd').valid()) {
    //if form is valid, unbind the submit action and submit the form
    $('#frmCreateNewAd').unbind('submit').submit();
  }
});

I thought that maybe the problem was trying to disable the bind from within a bind... but I also tried this with the exact same results

//bind custom form action
$('#frmCreateNewAd').bind("submit", function(e){
  //disable default action
  e.preventDefault();
  //remove previous validation data
  $('#frmCreateNewAd').removeData("previousValue");
  //validate form
  $('#frmCreateNewAd').valid();
});

//When user submits form
$('#frmCreateNewAd').submit(function (e) {
  //remove previous validation data
  $("#frmCreateNewAd").removeData("previousValue");
  //check if form is valid
  if($('#frmCreateNewAd').valid()) {
    //if valid, unbind custom submit and submit the default action
    $(this).unbind('submit').submit();
  }
  else {
    //if invalid, ensure default is still prevented
    e.preventDefault();
  }
});

I feel like maybe I am double binding the submit action? Has any one else had to overcome this problem?

UPDATE:

Validator code:

From a global file:

if ($.validator) {
    $.validator.messages.required = 'Required field';
    $.validator.addMethod("zipcode", function(postalcode, element) { return this.optional(element) || postalcode.match(/(^\d{5}(-\d{4})?$)|(^[ABCEGHJKLMNPRSTVXYabceghjklmnpstvxy]{1}\d{1}[A-Za-z]{1} ?\d{1}[A-Za-z]{1}\d{1})$/); }, 'A valid Zip code is required');
    //$.validator.addMethod("urlcustom", function isUrl(str){ var regex = new RegExp("^((http|https|ftp)\://){0,1}([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&amp;%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&amp;%\$#\=~_\-]+))*$"); return regex.test(str); }, 'A valid URL is required');
    $.validator.addMethod("alphanumspaces", function alphanumspaces(value, element) { return this.optional(element) || value.match(/^[A-Za-z0-9_\-]+(\s[A-Za-z0-9_\-]+)*$/); }, 'Only letters, numbers, underscores (_), hyphens (-), and single spaces are allowed.');
    $.validator.addMethod("alphanumspchars", function alphanumspchars(value, element) {return this.optional(element) || value.match(/^[A-Za-z0-9_\-,\.\#\/\'\"\?]+(\s[A-Za-z0-9_\-,\.\#\/\'\"\?]+)*$/); }, 'Only letters, numbers, single spaces, and simple punctuation (\'\"-,_.#/?) are allowed.' );
    $.validator.addMethod("alphaspaces", function alphaspaces(value, element) {return this.optional(element) || value.match(/^[A-Za-z]+(\s[A-Za-z]+)*$/); }, 'Only letters and single spaces are allowed.');
    $.validator.addMethod("alphaspspaces", function alphaspspaces(value, element) {return this.optional(element) || value.match(/^[A-Za-z\-\.\(\)]+(\s[A-Za-z0\-\.\(\)]+)*$/); }, 'Only letters, hyphens (-), periods (.), and single spaces allowed');
    $.validator.addMethod("numeric", function numeric(value, element) {return this.optional(element) || value.match(/^[0-9]+$/); }, 'Only numbers with no spaces are allowed.');                $.validator.addMethod("statecode", function statecode(value, element) {return this.optional(element) || value.match(/^(A[LKSZRAEP]|C[AOT]|D[EC]|F[LM]|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEHINOPST]|N[CDEHJMVY]|O[HKR]|P[ARW]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY]|alabama|alaska|arizona|arkansas|california|colorado|connecticut|delaware|florida|georgia|hawaii|idaho|illinois|indiana|iowa|kansas|kentucky|louisiana|maine|maryland|massachusetts|michigan|minnesota|mississippi|missouri|montana|nebraska|nevada|new\shampshire|new\sjersey|new\smexico|new\syork|north\scarolina|north\sdakota|ohio|oklahoma|oregon|pennsylvania|rhode\sisland|south\scarolina|south\sdakota|tennessee|texas|utah|vermont|virginia|washington|wyoming|d.c.)$/i); }, 'A valid state or two-letter state abbreviation is required.');
    $.validator.addMethod("isDollars", function isDollars(value, element) {return this.optional(element) || value.match(/[0-9]+(\.[0-9]{2})?$/); }, 'Must be a valid dollar amount, with or without decimal.');
    $.validator.addMethod("keywords", function keywords(value, element) {return this.optional(element) || value.match(/^[A-Za-z0-9]+(,?\s[A-Za-z0-9]+)*$/); }, 'Keywords may only contain letters, numbers, and single spaces. Keywords must be separated by a comma and single space (, )');
    $.validator.addMethod("notzero", function notzero(value, element) {return this.optional(element) || value.match(/(^[1-9]+[0-9]*$)|(^0+[1-9]$)/); }, 'Please enter a value greater than zero');
    $.validator.addMethod("urlOpt", function urlOpt(value, element) {return this.optional(element) || value.match(/^(((http|https|ftp)\:\/\/){0,1}([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&amp;%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(\/($|[a-zA-Z0-9\.\,\?\'\\\+&amp;%\$#\=~_\-]+))*)*$/); }, 'Please enter a properly formatted URL');
    $.validator.addMethod("noQuoteWrap", function noQuotes(value, element) {return this.optional(element) || value.match(/^[^\'\"].*[^\'\"]$/); }, 'Please remove leading or trailing quotes');
    $.validator.addMethod("phoneNum", function phoneNum(value, element) {return this.optional(element) || value.match(/^(1-|1\.|1)?(\([0-9]{3}\)|[0-9]{3})[\.\-]?[0-9]{3}[\.\-]?[0-9]{4}$/); }, 'Please enter a valid phone number, with or without hyphens (-), periods (.), or parenthesis ().');
    $.validator.addMethod("spaceStrip", function spaceStrip(value, element) { return this.optional(element) || value.match(/^[.]*$/); }, 'Removing leading and trailing whitespace');
    $.validator.addMethod("noScript", function noScript(value, element) { return this.optional(element) || value.match(/^((?!<script).)*$/); }, 'Script tags are not allowed');

    // Create and hide error message DOM elements
    var errorWrap = document.createElement('div');
    $(errorWrap).addClass('errorWrap hideError');
    var errorTop = document.createElement('div');
    $(errorTop).addClass('errorTop');
    var topSpan = document.createElement('span');
    var errorContent = document.createElement('div');
    $(errorContent).addClass('errorContent');
    var errorBottom = document.createElement('div');
    $(errorBottom).addClass('errorBottom');
    var bottomSpan = document.createElement('span');

    $("dl > dd").append(errorWrap);
    $("div.errorWrap").append(errorTop)
            .append(errorContent)
            .append(errorBottom);
    $("div.errorTop").append(topSpan);
    $("div.errorBottom").append(bottomSpan);

    //Set custom placement, highlighting, and unhighlighting
    $.validator.setDefaults({
                errorPlacement: function(error, element) {
                    if ($(element).attr("name") == "remnantList") {
                        $(element).parent().nextAll('.errorWrap').children('.errorContent').append(error);
                      }
                    else {
                        $(element).nextAll('.errorWrap').children('.errorContent').append(error);
                    }
                },
                highlight: function(element) {
                    if ($(element).attr("name") == "remnantList") {
                        $(element).parent().nextAll('.errorWrap').removeClass('hideError');
                    }
                    else {
                        $(element).nextAll('.errorWrap').removeClass('hideError');
                    }
                },
                unhighlight: function(element) {
                    if ($(element).attr("name") == "remnantList") {
                        $(element).parent().nextAll('.errorWrap').addClass('hideError');
                      }
                    else {
                        $(element).nextAll('.errorWrap').addClass('hideError');
                    }
                },
                onkeyup: false

    });

From js file specific to the page:

$('form').validate({
            errorElement: 'span',
            onkeyup: true,
            onfocusout: true,
            rules: {
                    'adName': { required: true, spaceStrip: { depends:  function() { $(this).val($.trim($(this).val())); return false; } }, maxlength:200 },
                    'adText': { alphanumspchars: true, maxlength:1000, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'thirdPartyImpressionTrackingUrl': { noQuoteWrap: true, maxlength:1000, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'thirdPartyClickTrackingUrl': { noScript: true, noQuoteWrap: true, maxlength:1000, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.destinationUrlView': { required: { depends: destinationUrlRequired }, noQuoteWrap: { depends: isBannerAndFirstFieldIsUrl }, /*number: { depends: isBannerAndIsClickToCall },*/ minlength: function() { return isBannerAndIsClickToCall() ? 10 : false; }, maxlength:1000, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.destinationFile': { required: { depends: isBannerAndDestinationFile }, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[0].multipartFile': { required: { depends: requiredFileUpload }, accept:'jpg|gif|png', spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[1].multipartFile': { required: { depends: requiredFileUpload }, accept:'jpg|gif|png', spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[2].multipartFile': { required: { depends: requiredFileUpload }, accept:'jpg|gif|png', spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[3].multipartFile': { required: { depends: requiredFileUpload }, accept:'jpg|gif|png', spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[4].multipartFile': { required: { depends: requiredFileUpload }, accept:'jpg|gif|png', spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[5].multipartFile': { required: { depends: requiredFileUpload }, accept:'jpg|gif|png', spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[6].multipartFile': { required: { depends: requiredFileUpload }, accept:'jpg|gif|png', spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'videoAdCommand.interactions[0].destinationUrl': { required: { depends: isVideoAndVisible }, maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'videoAdCommand.interactions[1].destinationUrl': { required: { depends: isVideoAndVisible }, maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'videoAdCommand.interactions[2].destinationUrl': { required: { depends: isVideoAndVisible }, maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'videoAdCommand.interactions[3].destinationUrl': { required: { depends: isVideoAndVisible }, maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'videoAdCommand.interactions[4].destinationUrl': { required: { depends: isVideoAndVisible }, maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[0].destinationUrl': { maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[1].destinationUrl': { maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[2].destinationUrl': { maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[3].destinationUrl': { maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[4].destinationUrl': { maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[0].thirdpartyImpressionUrl': { maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[1].thirdpartyImpressionUrl': { maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[2].thirdpartyImpressionUrl': { maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[3].thirdpartyImpressionUrl': { maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[4].thirdpartyImpressionUrl': { maxlength:1000, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[0].thirdpartyClickUrl': { maxlength:1000, noScript: true, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[1].thirdpartyClickUrl': { maxlength:1000, noScript: true, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[2].thirdpartyClickUrl': { maxlength:1000, noScript: true, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[3].thirdpartyClickUrl': { maxlength:1000, noScript: true, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'bannerAdCommand.bannerFiles[4].thirdpartyClickUrl': { maxlength:1000, noScript: true, noQuoteWrap: true, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'videoAdCommand.videoMultipartFile': { required: { depends: isVideoAndNoneExists }, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } },
                    'videoAdCommand.duration': { required: { depends: isVideo }, spaceStrip: { depends: function() { $(this).val($.trim($(this).val())); return false; } } }
            },
            messages: {
                    'bannerAdCommand.destinationUrlView': { url: 'Valid URL is required' },
                    'bannerAdCommand.bannerFiles[0].multipartFile': { required: bannerMissing, accept: bannerType },
                    'bannerAdCommand.bannerFiles[1].multipartFile': { required: bannerMissing, accept: bannerType },
                    'bannerAdCommand.bannerFiles[2].multipartFile': { required: bannerMissing, accept: bannerType },
                    'bannerAdCommand.bannerFiles[3].multipartFile': { required: bannerMissing, accept: bannerType },
                    'bannerAdCommand.bannerFiles[4].multipartFile': { required: bannerMissing, accept: bannerType },
                    'bannerAdCommand.bannerFiles[5].multipartFile': { required: bannerMissing, accept: bannerType },
                    'bannerAdCommand.bannerFiles[6].multipartFile': { required: bannerMissing, accept: bannerType },
                    'videoAdCommand.videoMultipartFile': { required: videoMissing, accept:'mov|mp4|wmv|avi' }
            }
    });
2012-04-04 22:29
by Eric Westbrook


0

I ended up fixing this by adding a mid-tier validator method to reject the values from the server using the same regex I used on jquery validator to refuse script tags. This isn't the way I was hoping to resolve this, but it works. As the problem appears to be some bug within jquery validator's submit handler under some extremely specific circumstances, I thought it better to get around and move on. Thanks very much to everybody who provided input.

2012-04-09 21:06
by Eric Westbrook


0

How about returning false when the form does not validate , wouldnt that prevent the form from being submitted ? .

Correct me if i am wrong is this what you are trying to do: 1) Validate user input 2) If all inputs are correct submit form 3) Else display errors

Your problem is it still submits the form even when though their are validation errors.

2012-04-04 22:50
by Krithika.Amirth
Hi Krithika. You're correct on what I want to accomplish. The form should not submit unless all fields are valid. If fields have errors, the form should not submit and the errors should display. The fact that errors DO display but the form submits anyway is what really has me scratching my head - Eric Westbrook 2012-04-04 22:53
Eric take a look at http://docs.jquery.com/Plugins/Validation/valid - Krithika.Amirth 2012-04-04 23:40
Did to try calling validate() before called valid() on the for - Krithika.Amirth 2012-04-04 23:40
I did. The form is specifically saving after failed validation. So validate() has clearly already been called - Eric Westbrook 2012-04-05 17:40


0

Are you using a jQuery plugin for the validation or a custom script? I would like to perform a few tests myself.

2012-04-04 23:02
by trickyzter
I'm using the jquery validation plugin. Yes - Eric Westbrook 2012-04-04 23:03
Eric, could you also update your html to reflect the actual form if possible. In addition the setup params for the validation - trickyzter 2012-04-04 23:13
Eric, having reviewed the documentation, is there any reason why you chose not to use the submitHandler/invalidHandler options passed into the validate method? See: http://docs.jquery.com/Plugins/Validation/validate#toption - trickyzter 2012-04-04 23:21
I added all of the validator code. The form is actually huge and even more complex than the custom rules. Given that validation works in all cases besides this instance, I have a hard time thinking it's anything other than a bug in jquery validator i have to find a way around. Could it have to do with being a multipart form - Eric Westbrook 2012-04-04 23:23
The enctype would not impact it in any way. Did you see me comment above - trickyzter 2012-04-04 23:28
Sorry trickyzter, I tried using submitHandler and invalidHandler but was still getting the same results. Since the default handlers are otherwise operating as expected, and since the element is being marked as invalid but the form submits anyway, it seemed like a dead end to pursue further - Eric Westbrook 2012-04-05 17:39


0

This worked for me:

    $(document).ready(function () {
        $("#frmCreateNewA").validate();

        //bind custom form action
        $('#frmCreateNewAd').bind("submit", function (e) {
            //disable default action
            e.preventDefault();

            alert($('#frmCreateNewAd').valid());
            //remove previous validation data
            $('#frmCreateNewAd').removeData("previousValue");
            //check if form is valid
            if (!$('#frmCreateNewAd').valid()) {

                return false
            }

        });

    });

   <form id="frmCreateNewAd" action="javascript:alert('success!');">

 <input id="txttest" type="text" class="required checkUrl" />
 <input class="btnSave" type="submit" value="Save" />

 </form>

where "class" attribute specifies the rules : http://docs.jquery.com/Plugins/Validation/rules

take a look at docs.jquery.com/Plugins/Validation/valid

2012-04-05 00:03
by Krithika.Amirth
I just gave this a shot and I'm still getting the same results as everything else that I try. Everything works correctly until you try to save a form, change a URL field to include a script tag and click save. I still get the same symptoms of the error message appearing (which means an error has been triggered), but the form submits anywa - Eric Westbrook 2012-04-05 20:57
Ads