web-dev-qa-db-ja.com

JQuery Validateプラグインを使用して、同じ名前の複数のフォームフィールドを検証する

同じ名前の入力フィールドを持つ動的に生成されたフォームがあります(例: "map")。フォームハンドラコード(Perl/CGI)は入力値の配列(この場合は_@map_)を処理するように設計されているため、フィールド名を変更したり、一意のフィールド名を生成したりするオプションはありません。

このような状況でフォームを検証するために、JQuery Validate Plugin を使用するにはどうすればよいですか?具体的には、サブミットされた配列の1つの要素に特定の固定値が必要です。現在、serializeArray()を使用してJSONオブジェクトを作成し、それを走査して条件が満たされていることを確認するカスタムイベントハンドラーを使用しています。しかし、私はアプリケーションの残りの部分でValidate Pluginを使用しているため、ここでも同じプラグインを使用してそのようなケースを処理できるかどうか疑問に思っていました。

ご清聴ありがとうございました。

47
Ya. Perelman

最終的に複数のフィールドで検証を行う最も簡単な方法を試したときに、さまざまなことを検索して試してみました。各フィールドとそのクローンは、各セットに固有のクラスを共有します。そのクラスで入力をループし、通常どおり検証ルールを追加しました。これが他の誰かに役立つことを願っています。

    $("#submit").click(function(){
    $("input.years").each(function(){
        $(this).rules("add", {
            required: true,
            messages: {
                required: "Specify the years you worked"
            }
        } );            
    });

    $("input.employerName").each(function(){
        $(this).rules("add", {
            required: true,
            messages: {
                required: "Specify the employer name"
            }
        } );            
    }); 

    $("input.employerPhone").each(function(){
        $(this).rules("add", {
            required: true,
            minlength: 10,
            messages: {
                required: "Specify the employer phone number",
                minlength: "Not long enough"
            }
        } );            
    }); 

    $("input.position").each(function(){
        $(this).rules("add", {
            required: true,
            messages: {
                required: "Specify your position"
            }
        } );            
    });             

    $("input.referenceName").each(function(){
        $(this).rules("add", {
            required: true,
            messages: {
                required: "Specify the reference name"
            }
        } );            
    });         

    $("input.referencePhone").each(function(){
        $(this).rules("add", {
            required: true,
            minlength: 10,
            messages: {
                required: "Specify your reference phone number",
                minlength: "Not long enough"
            }
        } );            
    });

// Now do your normal validation here, but don't assign rules/messages for the fields we just set them for





});
39
jason

@scampbellの回答にコメントできないので、評判ポイントについてか、スレッドが閉じたばかりかどうかはわからないが、彼の回答に貢献している。

ソースファイルjquery.validationを変更する代わりに、それを必要とするページでのみ編集する必要がある関数を単純にオーバーライドできます。

例は次のとおりです。

$.validator.prototype.checkForm = function() {
    //overriden in a specific page
    this.prepareForm();
    for (var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++) {
        if (this.findByName(elements[i].name).length !== undefined && this.findByName(elements[i].name).length > 1) {
            for (var cnt = 0; cnt < this.findByName(elements[i].name).length; cnt++) {
                this.check(this.findByName(elements[i].name)[cnt]);
            }
        } else {
            this.check(elements[i]);
        }
    }
    return this.valid();
};

これは最良の解決策ではないかもしれませんが、少なくとも、新しいバージョンがリリースされたときに後で置き換えられる可能性のあるソースファイルの編集は避けます。オーバーライドされた関数が破損する場合と破損しない場合

59
Ahmed Galal

私が知っている古いスレッドですが、同じ問題の修正を探して見つけました。

よりエレガントなソリューションがここに投稿されました: http://web-funda.blogspot.com/2009/05/jquery-validation-for-array-of-input.html

Jquery.validate.jsを編集し、checkFormを

    checkForm: function() {
    this.prepareForm();
    for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
        if (this.findByName( elements[i].name ).length != undefined && this.findByName( elements[i].name ).length > 1) {
            for (var cnt = 0; cnt < this.findByName( elements[i].name ).length; cnt++) {
                    this.check( this.findByName( elements[i].name )[cnt] );
            }
        } else {
            this.check( elements[i] );
        }
    }
    return this.valid();
}
55
scampbell

プラグインの作成者であるJörnZaeffererのメールから、ラジオボタンとチェックボックスを除いてフィールド名が一意である必要があることを知りました。

11
Ya. Perelman

ジェイソンの答えはトリックを行いますが、私がこれを行ったすべてのフォームに余分なクリックイベントを追加したくありませんでした。

私の場合、同じフィールド名を持っている場合でも、「[]」で終わる名前を異なるものと見なす検証プラグインがあります。これを行うために、jquery.validate.jsのロード後にこれら2つの内部メソッドを上書きしました。

$.validator.prototype.elements= function() {
var validator = this,
    rulesCache = {};

// select all valid inputs inside the form (no submit or reset buttons)
// workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved
return $([]).add(this.currentForm.elements)
.filter(":input")
.not(":submit, :reset, :image, [disabled]")
.not( this.settings.ignore )
.filter(function() {
    !this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);

    // select only the first element for each name (EXCEPT elements that end in []), and only those with rules specified
    if ( (!this.name.match(/\[\]/gi) && this.name in rulesCache) || !validator.objectLength($(this).rules()) )
        return false;

    rulesCache[this.name] = true;
    return true;
});
};


$.validator.prototype.idOrName = function(element) {

// Special edit to get fields that end with [], since there are several [] we want to disambiguate them
// Make an id on the fly if the element doesnt have one
if(element.name.match(/\[\]/gi)) {
    if(element.id){
        return element.id;
    } else {
        var unique_id = new Date().getTime();

        element.id = new Date().getTime();

        return element.id;
    }
}

return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
};
4
Steve Farthing

これが私がやった方法です。以前に提案された方法よりも少し簡単です:

function validateTab(tab) {
    var valid = true;
    $(tab).find('input').each(function (index, elem) {
        var isElemValid = $("#registrationForm").validate().element(elem);
        if (isElemValid != null) { //this covers elements that have no validation rule
            valid = valid & isElemValid;
        }
    });

    return valid;
}

私の場合、一度にすべてのフィールドを検証したくないため、ウィザードが(3つのステップで)さらに複雑になりました。基本的にコンポーネントをタブに配置し、最初のタブが有効な場合は、最後のタブに到達するまで次のタブに移動し、その後すべてのデータを送信します。したがって、tabパラメータには実際のタブ要素(div)があります。次に、すべての入力要素の子を自分のタブにループし、有効性をチェックします。

それ以外はすべて標準です。


完全を期すために、残りのコードは次のとおりです。フォームの送信がどのように行われ、バリデーターがどのように見えるかです。

<a href="javascript:moveToNextTab(1)" class="button next">Submit</a>

そして、ここでjs関数が呼び出されました:

function moveToNextTab(currentTab) {
    var tabs = document.getElementsByClassName("tab");
    //loop through tabs and validate the current one.
    //If valid, hide current tab and make next one visible.
}

私はこれらの検証ルールを使用しています(JQuery.readyで作成します):

$("#registrationForm").validate({
    rules: {
        birthdate: {
            required: true,
            date: true
        },
        name: "required",
        surname: "required",
        address: "required",
        postalCode: "required",
        city: "required",
        country: "required",
        email: {
            required: true,
            email: true
        }
    }
});
3
Stef

入力の未使用の属性を使用して元の名前を保存し、インデックスを添付して名前を変更するだけです:

function addMultiInputNamingRules(form, field, rules){    
    $(form).find(field).each(function(index){
    $(this).attr('alt', $(this).attr('name'));
    $(this).attr('name', $(this).attr('name')+'-'+index);
    $(this).rules('add', rules);
});

}

function removeMultiInputNamingRules(form, field){    
    $(form).find(field).each(function(index){
    $(this).attr('name', $(this).attr('alt'));
    $(this).removeAttr('alt');
});

}

次に、バリデータを設定した後:

addMultiInputNamingRules('#form-id', 'input[name="multifield[]"]', { required:true });

検証が終了したら、次のように戻ります。

removeMultiInputNamingRules('#form-id', 'input[alt="multifield[]"]');

- お役に立てれば!

3
Matt Kircher

「jQuery検証プラグイン1.7」を使用しています。

同じ名前を共有する複数の「$(:input)」要素が検証されない問題

は$ .validator.elementメソッドです。

elements: function() {
        var validator = this,
            rulesCache = {};

        // select all valid inputs inside the form (no submit or reset buttons)
        // workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved
        return $([]).add(this.currentForm.elements)
        .filter(":input")
        .not(":submit, :reset, :image, [disabled]")
        .not( this.settings.ignore )
        .filter(function() {
            !this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);

            // select only the first element for each name, and only those with rules specified
            if ( this.name in rulesCache || !validator.objectLength($(this).rules()) )
                return false;

            rulesCache[this.name] = true;
            return true;
        });
    },

条件

if(rulesCacheのthis.name || .....

同じ名前trueを共有する2番目と次の要素について評価します。

解決策は次の条件を持つことです。

(this.id || this.name)in rulesCache

JSピュリタン、すみません、(this.id || this.name)は100%ではありません...

もちろん、

rulesCache [this.name] = true;

行も適切に変更する必要があります。

したがって、$。validator.prototype.elementsメソッドは次のようになります。

$(function () {
if ($.validator) {
    //fix: when several input elements shares the same name, but has different id-ies....
    $.validator.prototype.elements = function () {

        var validator = this,
            rulesCache = {};

        // select all valid inputs inside the form (no submit or reset buttons)
        // workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved
        return $([]).add(this.currentForm.elements)
        .filter(":input")
        .not(":submit, :reset, :image, [disabled]")
        .not(this.settings.ignore)
        .filter(function () {
            var elementIdentification = this.id || this.name;

            !elementIdentification && validator.settings.debug && window.console && console.error("%o has no id nor name assigned", this);

            // select only the first element for each name, and only those with rules specified
            if (elementIdentification in rulesCache || !validator.objectLength($(this).rules()))
                return false;

            rulesCache[elementIdentification] = true;
            return true;
        });
    };
}

});

2
Motlicek Petr

ポイントが足りないかもしれませんが、バリデーターが複数の名前で動作しないため(試してみました...失敗しました!)フォームを変更して、名前を動的に変更し、ルールを設定し、送信時に名前を設定解除しました。

2つのメソッド(wlogのものは無視し、コンソールに出力するだけです):

// convert the field names into generated ones to allow fields with the same names 
// to be validated individually. The original names are stored as data against the
// elements, ready to be replaced. The name is replaced with
// "multivalidate-<name>-<id>", e.g. original => 'multivalidate-original-1'

function setGeneratedNamesWithValidationRules(form, fields, rules) {

    var length = fields.length;

    for (var i=0; i < length; ++i ){
        var name = fields[i];

        var idCounter = 0;  
        // we match either the already converted generator names or the original
        $("form [name^='multivalidate-" + name + "'], form [name='" + name + "']").each(function() {
            // identify the real name, either from the stored value, or the actual name attribute
            var realName = $(this).data('realName');
            if (realName == undefined) {
                realName = $(this).attr("name");
                $(this).data('realName', realName);
            }

            wlog("Name: " + realName + " (actual: " + $(this).attr("name") + "), val: " + $(this).val() + ". Rules: " + rules[realName]);
            $(this).attr("name", "multivalidate-" + realName + "-" + idCounter);
            if (rules[realName]) {
                $(this).rules("add", rules[realName]);
            }
            idCounter++;
        });
    }
}

function revertGeneratedNames(form, fields) {

    var length = fields.length;

    for (var i=0; i < length; ++i ){
        var name = fields[i];
        wlog("look for fields names [" + name + "]");

        $("form [name^='multivalidate-" + name + "']").each(function() {
            var realName = $(this).data('realName');
            if (realName == undefined) {
                wlog("Error: field named [" + $(this).attr("name") + "] does not have a stored real name");
            } else {
                wlog("Convert [" + $(this).attr("name") + "] back to [" + realName + "]");
                $(this).attr("name", realName);
            }
        });
    }
}

フォームのロード時、および別の行を動的に追加するたびに、setメソッドを呼び出します。

setGeneratedNamesWithValidationRules($("#my-dynamic-form"), ['amounts'], { 'amounts': 'required'} );

これにより、名前が変更され、個々の検証が可能になります。

SubmitHandler:検証後、revertを呼び出します。

revertGeneratedNames(form, ['amounts']);

データを投稿する前に元の名前に切り替えます。

1
Alfonzo

私にとって、これはデバッグを無効にすることで非常に簡単に解決されました

 $("#_form").validate({
    debug:false,
    //debug: true,
    ...
    });
0
Ebrahim

HTMLフォームの仕組みを誤解していると思います。 1つのデータフィールドに1つまたは複数のオプションを選択できる複数のチェックボックスとボタンを除き、すべてのフォーム要素には一意の名前が必要です。

あなたの場合、JQuery検証だけでなく、サーバー側のフォーム検証も失敗します。これは、データフィールドに入力を割り当てることができないためです。ユーザーにプレネーム、ラストネーム、電子メールアドレス、ファックス(オプション)を入力してもらい、すべての入力フィールドにname="map"

次に、送信時にこれらのリストを受け取ります。

map = ['Joe','Doe','joe.doeAThotmail.com','++22 20182238'] //All fields completed
map = ['Joe','Doe','joe.doeAThotmail.com'] //OK, all mandatory fields completed 
map = ['Doe', 'joe.doeAThotmail.com','++22 20182238']//user forgot prename, should yield error

このフォームを確実に検証することは不可能であることがわかります。

Perlフォームハンドラのドキュメントを再検討するか、自分で作成した場合はそれを変更することをお勧めします。

0
Franz