表格提交一次提交,然后每次加倍

时间:2015-09-25 13:58:22

标签: javascript jquery forms

所以我构建了这个插件,在测试它时一切运行良好,直到我最终到达插件的onSubmit部分。发生的事情是表单会成功提交一次,但之后它会提交的次数增加一倍。我不知道这是怎么回事,因此我转向你们寻求帮助。

我提供了一个演示表单,插件使用表单和插件本身进行操作的方式。由于我不确定它在插件中的来源,因此我提供了完整的源代码。如果还有其他任何需要帮助,请告诉我。

HTML

<form id='test'>
    <div class='form-group'>
        <input type='text' id='data' class='form-control' />
    </div>
    <button type='submit' class='btn btn-default'>Submit</button>
</form>

的javascript

    $(function(){
        $('#test').validator({
            controls:{
                data : {
                    validate : 'notEmpty'
                }
            },
            onSubmit : function(){
                alert("success");

                // destroy the instance
                $('#test').validator('destroy');

                // get the original options
                var options = $('#test').validator('getSettings');

                // re initialize the plugin for the form
                $('#test').validator(options);
            }
        });
    });

validator.js

(function($){
    var _defaults = null;
    // functions object where the validator functions are stored for use
    var functions = {
        notEmpty : function(value){
            return value && $.trim(value).length > 0;
        },
        required : function(value){
            return value && $.trim(value).length > 0;
        },
        isEmail : function(value){
            var check = true;
            if(value.length)
                check = /^([^@\s\t\n]+\@[\w\d]+\.[\w]{2,3}(\.[\w]{2})?)$/.test(value);
            return check;
        },
        isPhoneNumber : function(value){
            var check = true;
            if(value.length)
                check = /^(\d\-)?\(?\d{3}\)?[\-|\s]?\d{3}[\-|\s]?\d{4}$/.test(value);
            return check;
        }, 
        isNumber : function(value){
            var check = true;
            if(value.length)
                check = /^[+-]?\d+(\.\d+)?$/.test(value);
            return check;
        },
        isSSN : function(value){
            var check = true;
            if(value.length)
                check = /^\d{3}\-?\d{2}\-?\d{4}$/.test(value);
            return check;
        },
        isString : function(value){
            var check = true;
            if(value.length)
                check = /^\D+$/.test(value);
            return check;
        },
        isURL : function(value){
            var check = true;
            if(value.length)
                check = /^([http\:\/\/]+)?([a-zA-Z]+)?\.?[a-zA-Z0-9\-]+\.[a-zA-Z]+$/.test(value);
            return check;
        },
        isDateTime : function(value, regex){
            var check = true;
            if(regex == null){
                return true;
            }
            var regexChars = regex.split("");
            var pattern = "^";
            for(var i = 0; i < regexChars.length; i++){
                switch(regexChars[i]){
                    case "d" : 
                    case "j" :
                        pattern = pattern + "(0?[1-9]|[12][0-9]|3[01])";
                        break;
                    case "D":
                        pattern = pattern + "(Sun|Mon|Tue|Wed|Thu|Fri|Sat)";
                    case "l" :
                        pattern = pattern + "(Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)";
                        break;
                    case "F" :
                        pattern = pattern + "(January|February|March|April|May|June|July|August|September|October|November|December)";
                        break;
                    case "M" :
                        pattern = pattern + "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)";
                        break;
                    case "m" :
                    case "n" :
                        pattern = pattern + "(0?[1-9]|1[012])";
                        break;
                    case "Y" :
                    case "y" :
                        pattern = pattern + "(19|20)?[\\d]+";
                        break;
                    case "a" :
                    case "A" :
                        pattern = pattern + "([AaPp][Mm])";
                        break;
                    case "g" :
                    case "G" :
                    case "h" :
                    case "H" :
                        pattern = pattern + "(0?[0-9]|1[012]|2[0123])";
                        break;
                    case "i" :
                    case "s" :
                        pattern = pattern + "([012345][0-9])";
                        break;
                    case "/" :
                        pattern = pattern + "[/]";
                        break;
                    case ":" :
                        pattern = pattern + "[:]";
                        break;
                    case "." : 
                        pattern = pattern + "[.]";
                        break;
                    case " " :
                        pattern = pattern + "[ ]";
                        break;
                    case "," :
                        pattern = pattern + "[,]";
                        break;
                    case "-" :
                        pattern = pattern + "[-]";
                        break;
                }
            }
            pattern = pattern+"$";

            pattern = new RegExp(pattern, 'i');

            if(value.length)
                check = pattern.test(value);
            return check;
        },
        groupNotEmpty : function(value){
            return value.length > 0;
        },
        isRoutingNumber : function(value){
            //run through each digit and calculate the total
            var n = 0;
            for(var i = 0; i < value.length; i += 3){
                n += parseInt(value.charAt(i), 10)*3 + parseInt(value.charAt(i+1), 10)*7 + parseInt(value.charAt(i+2), 10);
            }
            //if the resulting sum is an even multiple of ten (but not zero), the aba routing number is good
            if(n != 0 && n % 10 == 0){
                return true;
            }else{
                return false;
            }
        },
        isMacAddress : function(value){
            var check = true;
            if(value.length){
                check = /^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$/.test(value);
            }
            return check;
        },
         isIPAddress : function(value){
            var check = true;
            if(value.length){
                check = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(value);
            }
            return check;
        },
        validPassword : function(value, selector){
            var form = this.$form;
            var that = this;
            var check = false;
            var strength = 0;

            if(value.length >= 1){
                 strength = 4;   
            }
            // password mixins
            var passwordChars = value.split('');
            var count = 0; // keep track of the characters
            for(p in passwordChars){
                count++;
                if(count < 8){
                    strength += 5;
                }else if(count >= 8 && count < 20){
                    strength += 3;
                }else if(count >= 20){
                    strength += 2;
                }
                if(/[0-9]/.test(passwordChars[p])){
                    strength += 3;
                }
                if(/[a-z]/.test(passwordChars[p])){
                    strength += 1;
                }
                if(/[A-Z]/.test(passwordChars[p])){
                    strength += 2;
                }
                if(/[!$@#]/.test(passwordChars[p])){
                    strength += 4;
                }

            }
            var progressBarHolder = $(form).find(selector).closest('.form-group');
            var progressBar = $(progressBarHolder).find('.progress-bar');
            var progressBarValue = strength;
            if(strength < 50){
                $(progressBar).css({
                    'width' : progressBarValue+'%',
                    'background-color' : '#D9534F'
                });
                $(progressBar).html(progressBarValue+'%');
            }else if(strength >= 50 && strength < 80){
                $(progressBar).css({
                    'width' : progressBarValue+'%',
                    'background-color' : '#F0AD4E'
                });
                $(progressBar).html(progressBarValue+'%');
            }else if(strength >= 80 && strength <= 100){
                $(progressBar).css({
                    'width' : progressBarValue+'%',
                    'background-color' : '#5CB85C'
                });
                $(progressBar).html(progressBarValue+'%');
            }else if(strength > 100){
                $(progressBar).css({
                    'width' : '100%',
                    'background-color' : '#5CB85C'
                });
                $(progressBar).html('100%');
            }
            if(strength >= 6){
                check = true;
            }
            return check;
        },
        equalTo : function(value, selector){
            var form = this.$form;
            var check = false;
            var checkValue = $(form).find(selector).val();
            if(value.length){
                if(value === checkValue){
                    check = true;
                }
            }
            return check;
        },
        isCreditCard : function(value){
            var that = this;
            var check = false;
            var value = value.replace(/[ -]/g, '');
            var card_types = [
                {
                    name : 'amex',
                    pattern: /^3[47]/,
                    valid_length: [15]
                }, {
                    //diners_club_carte_blanche
                    name: 'dccb',
                    pattern: /^30[0-5]/,
                    valid_length: [14]
                }, {
                    //diners_club_international
                    name: 'dci',
                    pattern: /^36/,
                    valid_length: [14]
                }, {
                    name: 'jcb',
                    pattern: /^35(2[89]|[3-8][0-9])/,
                    valid_length: [16]
                }, {
                    name: 'laser',
                    pattern: /^(6304|670[69]|6771)/,
                    valid_length: [16, 17, 18, 19]
                }, {
                    //visa_electron
                    name: 'electron',
                    pattern: /^(4026|417500|4508|4844|491(3|7))/,
                    valid_length: [16]
                }, {
                    name: 'visa',
                    pattern: /^4/,
                    valid_length: [16]
                }, {
                    //mastercard
                    name: 'mc',
                    pattern: /^5[1-5]/,
                    valid_length: [16]
                }, {
                    name: 'maestro',
                    pattern: /^(5018|5020|5038|6304|6759|676[1-3])/,
                    valid_length: [12, 13, 14, 15, 16, 17, 18, 19]
                }, {
                    name: 'discover',
                    pattern: /^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)/,
                    valid_length: [16]
                }
            ];

            if(value.length){
                var exists = false;
                var matches = false;
                var validlength = false;
                var validLuhn = false;
                var cardname = "";
                that.setCreditCardImage(cardname);
                for(var name in card_types){
                    if(value.match(card_types[name].pattern)){
                        matches = true;
                    }
                    if(card_types[name].valid_length.indexOf(value.length) > -1){
                        validlength = true;
                    }
                    if(matches && validlength){
                        cardname = card_types[name].name.toLowerCase();
                        break;
                    }
                }
                if(matches && validlength){
                    var digit, n, sum, j, len, ref1;
                    sum = 0;
                    ref1 = value.split('').reverse();
                    for(n = j = 0, len = ref1.length; j < len; n = ++j){
                        digit = ref1[n];
                        digit = +digit;
                        if(n % 2){
                            digit *= 2;
                            if(digit < 10){
                                sum += digit;
                            }else{
                                sum += digit - 9;
                            }
                        }else{
                            sum += digit;
                        }
                    }
                    if(sum % 10 === 0){
                        validLuhn = true;
                    }           
                }else{
                    return check;
                }
                if(matches && validlength && validLuhn){
                    check = true;
                    that.setCreditCardImage(cardname);
                    return check;
                }else{
                    that.setCreditCardImage();
                    return check;
                }
            }else{
                check = true;
                return check;
                that.setCreditCardImage();
            }

        },
        isZipCode : function(value){
            var check = true;
            if(value.length){
                check = /^\d{5}(?:[-\s]\d{4})?$/.test(value);
            }
            return check; 
        },
        isDependent : function(value, selector){
            var check = true;
            if(selector.length){
                if(selector.substring(0,1) === '_'){
                    selector = "[data-validator*=isDependent"+selector+"]";
                }
                if(!this.notEmpty(value)){
                    form.find(selector).each(function(){
                        if($(this).val() !== ''){
                            check = false;
                        }
                    });
                }
            }
            return check;
        },
        testRegex : function(value, regex){
            var check = true;
            var caret = regex.substring(0);
            var dollar = regex.substring(regex.length-1);
            if(caret != "^")
                regex = "^"+regex;
            if(dollar != "$")
                regex = regex+'$';
            if(value.length && regex.length){
                var pattern = new RegExp(regex, 'i');
                check = pattern.test(value);
            }
            return check;
        }
    };
    var selectors = [];
    // private function that sets the form control data-validator values
    var setControlData = function(selector, options){
        var validate = options.validate;
        var validations = "";
        if(Array.isArray(validate)){
            validations = validate.join("|");
        }else{
            validations = validate;
        }
        if(validations.indexOf('isDateTime') > -1 && typeof(options.dateFormat) != 'undefined' && typeof(options.dateFormat) == 'string'){
            validations = validations.replace(/isDateTime/g, 'isDateTime'+options.dateFormat);
        }
        if(validations.indexOf('equalTo') > -1 && typeof(options.equalTo) != 'undefined' && typeof(options.equalTo) == 'string'){
            validations = validations.replace(/equalTo/g, 'equalTo'+options.equalTo);
        }
        if(validations.indexOf('testRegex') > -1 && typeof(options.regex) != 'undefined' && typeof(options.regex) == 'string'){
            validations = validations.replace(/testRegex/g, 'testRegex'+options.regex);
        }
        $(selector).data('validator', validations);
    };

    // main function that validates the form itself
    var validator = function(selector){
            var rVal = true;
            var element = selector;
            var errors = 0;
            //check if there is a validator option for the specific input and that it has a value to it
            if($(element).data('validator')){

                // get the element type and split the pipe separated values into an array
                var value = null;
                var type = $(element).attr('type');
                var formGroup = null;
                if(type != "radio" && type != "checkbox"){
                    formGroup = $(element).closest('.form-group');
                    value = $(element).val();
                }else{
                    formGroup = $(element).closest('.form-group');
                    value = [];
                    $(formGroup).find('.radio, .checkbox, .radio-inline, .checkbox-inline').each(function(){
                        $(":checked", this).each(function(){
                            value.push($(this).val());
                        });
                    });
                }

                // check the .data('validator') string to account for interior pipes that may be used with regexes or selectors
                var validations = $(element).data('validator');
                validations = validations.replace(/\|\=/g, '%=');
                var holding = [];
                if(validations.indexOf('testRegex') > -1){
                    var hold = validations.substring(validations.indexOf('testRegex'), validations.lastIndexOf('/')+1);
                    holding.push(hold);
                    validations = validations.replace(hold, '');
                }
                validations = validations.replace("||", "|");
                validations = validations.split('|');
                validations = validations.concat(holding);
                for(var x in validations){
                    validations[x] = validations[x].replace('%=', '|=');
                }
                validations = validations.filter(function(n){return n != undefined && n != ""});
                for(var i = 0; i < validations.length; i++){
                    if(validations[i].indexOf('validPassword') !== -1){
                        var selector = validations[i].replace('validPassword', '');
                        !functions['validPassword'](value, selector) ? errors++ : null;
                    }else if(validations[i].indexOf('isDateTime') !== -1){
                        var regex = validations[i].replace('isDateTime', '');
                        !functions['isDateTime'](value, regex) ? errors++ : null;
                    }else if(validations[i].indexOf('equalTo') !== -1){
                        var selector = validations[i].replace('equalTo', '');
                        !functions['equalTo'](value, selector) ? errors++ : null;
                    }else if(validations[i].indexOf('isDependent') !== -1){
                        var selector = validations[i].replace('isDependent', '');
                        !functions['isDependent'](value, selector) ? errors++ : null;
                    }else if(validations[i].indexOf('testRegex') !== -1){
                        var regex = validations[i].replace('testRegex', '');
                        var regex = regex.substring(regex.indexOf('/')+1, regex.lastIndexOf('/'));
                        !functions['testRegex'](value, regex) ? errors++ : null;
                    }else{
                        !functions[validations[i]](value) ? errors++ : null;
                    }
                }
                if(errors > 0){
                    $(formGroup).addClass('has-error');
                }else{
                    $(formGroup).removeClass('has-error');
                }
                if(errors > 0) rVal = false;
            }else{
                formGroup = $(element).closest('.form-group');
                if(errors > 0){
                    $(formGroup).addClass('has-error');
                }else{
                    $(formGroup).removeClass('has-error');
                }
            }

            return rVal;
    };
    // object literal for the methods
    var methods = {
        // defining the individual methods inside of the literal
        init : function(options){

            // Repeat this process over each element in the selector
            return this.each(function(){
                var $this = $(this);
                var settings = options;
                _defaults = options;
                console.log(settings);
                // validation to make sure at least the bare minimum is supplied
                if(typeof(settings) == 'undefined'){
                    console.log("No options were supplied for this plugin. 'selectors' and 'onSubmit' are required. Please see documentation for assistance");
                    return false;
                }else if(typeof(settings.controls) != 'object'){
                    console.log("'selectors' must be an object");
                    return false;
                }else if(typeof(settings.onSubmit) != 'function'){
                    console.log("'onSubmit' is a callback function");
                    return false;
                }

                // if nothing else was wrong proceed to run the rest of the program here
                var controls = settings.controls;
                var bindInput = typeof settings.bindInput != 'undefined' && settings.bindInput != false ? true : false;
                var showErrorMessage = typeof settings.showErrorMessage != 'undefined' && settings.showErrorMessage != false ? true : false;

                for(var control in controls){
                    if(typeof controls[control] != 'object'){
                        console.log("controls."+control+" must be an object. Skipping this element");
                        continue;
                    }else if(typeof controls[control].validate == 'undefined'){
                        console.log("controls."+control+".validate must be defined");
                        continue;
                    }
                    $($this).find('input, textarea, select').each(function(){
                        if($(this).is('#'+control)){
                            setControlData('#'+control, controls[control]);
                            selectors.push('#'+control);    
                        }else if($(this).hasClass(control)){
                            setControlData('.'+control, controls[control]);
                            selectors.push('.'+control);
                        }
                    });
                }
                if(bindInput){
                    $($this).find('input, textarea, select').on('change keyup click select focus', function(){
                        for(var s in selectors){
                            validator(selectors[s]);
                        }
                    }); 
                }
                if(showErrorMessage){
                    $($this).prepend("<section id='errorAlert' class='form-group col-xs-12 hidden'><div class='alert alert-danger' ></div></section>");
                }
                // handle the form submission 
                $($this).submit(function(e){
                    e.preventDefault();
                    var errors = "";
                    var rVal = true;
                    for(selector in selectors){
                        if(!validator(selectors[selector])){
                            rVal = false;
                            if(showErrorMessage){
                                var pos = selectors.indexOf(selector);
                                var control = selectors[pos].replace(/[.#]/g, '');
                                if(typeof controls[control].errorMessage != "undefined" && typeof controls[control].errorMessage == 'string'){
                                    errors += "&bull; "+controls[control].errorMessage+"<br>";
                                }
                            }
                        }
                    }
                    if(rVal){
                        if(showErrorMessage){
                            $('#errorAlert').addClass('hidden');
                        }
                        settings.onSubmit();
                    }else{
                        if(showErrorMessage){
                            $('#errorAlert').removeClass('hidden');
                            $('#errorAlert > div').html(errors);
                            $('html, body').animate({
                                scrollTop : $('#errorAlert').offset().top
                            }, 1000);
                        }
                    }
                });
            });
        },
        checkControl : function(control, options){
            return this.each(function(){
                setControlData(control, options);
                validator(control);
                $(control).on('change keyup click select focus', function(){
                        validator(control);
                }); 
            });
        },
        clearControl : function(control){
            return this.each(function(){
                $(control).removeData('validator');
                $(control).off('change keyup click select focus');
                validator(control);             
            });
        },
        getSettings : function(){
            return _defaults;
        },
        destroy : function(){
            return this.each(function(){
                $(this).find('input, select, textarea').each(function(){
                    $(this).data('validator', '');
                    validator($(this));
                    $(this).removeData('validator');

                });
            });
        }
    }

    // the engine
    $.fn.validator = function(){

        // get the first argument passed if any
        var method = arguments[0];
        if(methods[method]){
            method = methods[method];
            arguments = Array.prototype.slice.call(arguments, 1);
        // if there was no argument or the argument is the default argument object then proceed to initialize
        }else if(typeof(method) == 'object' || !method){
            method = methods.init;
        }else {
            console.log("Method "+ method + " does not exist for this plugin");
            return this;
        }

        // return the result that is wanted based on what was passed in the initial arguments
        return method.apply(this, arguments);
    }
})(jQuery);

1 个答案:

答案 0 :(得分:1)

通过每次销毁并重新初始化插件,您依赖插件正确解除所有事件处理程序的绑定,在这种情况下它似乎不会。

可能更容易为插件提供一个方法来重置输入上的数据和值,从而为您提供一个新的表单,而无需重新初始化。