web-dev-qa-db-ja.com

jquery.validate.unobtrusiveが動的に挿入された要素で機能しない

私は_ASP.Net MVC3_を使用していますが、クライアント検証を使用するより簡単な方法は_jquery.validate.unobtrusive_を有効にすることです。サーバーから直接アクセスできるものであれば、すべて正常に動作します。

しかし、javascriptで新しい「入力」を挿入しようとすると、検証を再バインドするために$.validator.unobtrusive.parse()を呼び出す必要があることがわかりました。それでも、これらの動的に注入されたフィールドはすべて機能していません。

さらに悪いことに、_jquery.validate_を使用して手動でバインドしようとしましたが、どちらも機能していません。何かご意見は?

98
xandy

私の状況でこの問題を解決するjquery.validate.unobtrusiveライブラリの拡張機能を作成しました-興味深いかもしれません。

http://xhalent.wordpress.com/2011/01/24/applying-unobtrusive-validation-to-dynamic-content/

66
Xhalent

Xhalentのアプローチを試しましたが、残念ながらうまくいきませんでした。ロビンのアプローチはうまくいきましたが、うまくいきませんでした。動的に追加された要素に対してはうまく機能しましたが、JQueryを使用してすべての検証属性とスパンをDOMから削除しようとしても、検証ライブラリはそれらを検証しようとします。

ただし、「validationData」に加えてフォームの「unobtrusiveValidation」データを削除すると、検証する要素または検証しない要素を動的に追加および削除する魅力のように機能しました。

$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");
156
viggity

実際、@ viggityと@Robinsソリューションのシンプルさが本当に好きなので、簡単な小さなプラグインに変えました。

(function ($) {

    $.fn.updateValidation = function () {
        var $this = $(this);
        var form = $this.closest("form")
            .removeData("validator")
            .removeData("unobtrusiveValidation");

        $.validator.unobtrusive.parse(form);

        return $this;
    };
})(jQuery);

使用例:

$("#DischargeOutcomeNumberOfVisits")
    .attr("data-val-range-min", this.checked ? "1" : "2")
    .updateValidation();
41
lambinator

私は同じ問題を抱えています。同じフォームで$ .validator.unobtrusive.parse()を2回呼び出すことはできないことを発見しました。サーバーからフォームを最初にロードするとき、フォームは控えめなライブラリによって自動的に解析されます。入力要素をフォームに動的に追加し、$。validator.unobtrusive.parse()を再度呼び出すと、機能しません。 parseElement()についても同じことが言えます。

控えめなlibは、jquery validateプラグインのvalidateメソッドを呼び出して、すべてのルールとメッセージを設定します。問題は、プラグインが再度呼び出されたときに、指定された新しいルールセットを更新しないことです。

粗雑な解決策が1つ見つかりました。控えめなlibで解析メソッドを呼び出す前に、フォームバリデータを破棄します。

$('yourForm').removeData("validator");

現在では、検証メソッドが控えめなライブラリによって呼び出されると、動的に追加された入力を含むすべてのルールとメッセージが再作成されます。

お役に立てれば

32

私はMVC 4およびJQuery 1.8、を使用しています。AjaxまたはJqueryをDOMに動的に挿入したコンテンツをJqueryで検証できるようにするには、次のコードが必要なようです。

新しく追加された要素のJqueryオブジェクトを受け入れるモジュラー関数を作成しました。ボタンのクリック時にJqueryを使用してID tblContactsの新しいテーブルを複製した場合、jsファイルに以下の関数を含めます

function fnValidateDynamicContent(element) {
    var currForm = element.closest("form");
    currForm.removeData("validator");
    currForm.removeData("unobtrusiveValidation");
    $.validator.unobtrusive.parse(currForm);
    currForm.validate(); // This line is important and added for client side validation to trigger, without this it didn't fire client side errors.
}

次のように呼び出します:

fnValidateDynamicContent("#tblContacts")
8
Sundara Prabu

上記の答えとしてマークされたXhalentのソリューションから、少し拡張しました。

$.validator.unobtrusive.parseDynamicContent = function (selector) {
    var $selector = $(selector),
        $jqValUnob = $.validator.unobtrusive,
        selectorsDataValAttr = $selector.attr('data-val'),
        $validationInputs = $selector.find(':input[data-val=true]');

    if ((selectorsDataValAttr !== 'true') && 
        ($validationInputs.length === 0)) { 
        return; 
    }

    if (selectorsDataValAttr === 'true') {
        $jqValUnob.parseElement(selector, true);
    }

    $validationInputs.each(function () {
        $jqValUnob.parseElement(this, true);
    });

    //get the relevant form
    var $form = $selector.first().closest('form');

    $jqValUnob.syncValdators($form);
};

/* synchronizes the unobtrusive validation with jquery validator */
$.validator.unobtrusive.syncValdators = function ($form) {
    if ($.hasData($form[0])) {
        var unobtrusiveValidation = $form.data('unobtrusiveValidation'),
            validator = $form.validate();

        // add validation rules from unobtrusive to jquery
        $.each(unobtrusiveValidation.options.rules, function (elname, elrules) {
            if (validator.settings.rules[elname] == undefined) {
                var args = {};
                $.extend(args, elrules);
                args.messages = unobtrusiveValidation.options.messages[elname];
                $("[name='" + elname + "']").rules("add", args);
            } else {
                $.each(elrules, function (rulename, data) {
                    if (validator.settings.rules[elname][rulename] == undefined) {
                        var args = {};
                        args[rulename] = data;
                        args.messages = unobtrusiveValidation.options.messages[elname][rulename];
                        $("[name='" + elname + "']").rules("add", args);
                    }
                });
            }
        });
        // remove all validation rules from jquery that arn't in unobtrusive
        $.each(validator.settings.rules, function (elname, elrules) {
            if (unobtrusiveValidation.options.rules[elname] === undefined) {
                delete validator.settings.rules[elname];
            } else {
                $.each(elrules, function (rulename, data) {
                    if (rulename !== "messages" && unobtrusiveValidation.options.rules[elname][rulename] === undefined) {
                        delete validator.settings.rules[elname][rulename];
                    }
                });
            }
        });
    }        
};

$.validator.unobtrusive.unparseContent = function (selector) {
    var $selector = $(selector);

    // if its  a text node, then exit
    if ($selector && $selector.length > 0 && $selector[0].nodeType === 3) {
        return;
    }

    var $form = $selector.first().closest('form'), 
        unobtrusiveValidation = $form.data('unobtrusiveValidation');

    $selector.find(":input[data-val=true]").each(function () {
        removeValidation($(this), unobtrusiveValidation);
    });
    if ($selector.attr('data-val') === 'true') {
        removeValidation($selector, unobtrusiveValidation);
    }
    $.validator.unobtrusive.syncValdators($form);
};

function removeValidation($element, unobtrusiveValidation) {
    var elname = $element.attr('name');
    if (elname !== undefined) {
        $element.rules('remove');
        if (unobtrusiveValidation) {
            if (unobtrusiveValidation.options.rules[elname]) {
                delete unobtrusiveValidation.options.rules[elname];
            }
            if (unobtrusiveValidation.options.messages[elname]) {
                delete unobtrusiveValidation.options.messages[elname];
            }
        }
    }
}

したがって、基本的には上記のXhalentのソリューションと同じように機能しますが、domから削除する要素のルールを削除する機能を追加しました。したがって、Domから要素を削除し、それらの検証ルールも削除する場合は、次を呼び出します。

$.validator.unobtrusive.unparseContent('input.something');
2
Evan Larsen

ルール関数 をjquery検証ドキュメントから直接使用しないのはなぜですか。このような:

$('#newField0').rules('add', {
    required: true,
    minlength: 2
});
//use Html.ValidationMessage will renders a span element, unobtrusive need it to display errors
$('@Html.ValidationMessage("newField0")').insertAfter('#newField0');
2
zhangfx

私は機敏さの答えを試してみましたが、最初はすべてうまくいったようです。しかし、しばらくすると、追加した項目が動的になるほど検証が非常に遅くなることに気付きました。その理由は、彼のソリューションはイベントハンドラーのバインドを解除せず、毎回新しいハンドラーを追加するからです。したがって、5つのアイテムを追加すると、検証は1回だけではなく6回実行されます。これを修正するには、removeData呼び出しに追加してイベントのバインドを解除する必要があります。

$("form").removeData("validator")
         .removeData("unobtrusiveValidation")
         .off("submit.validate click.validate focusin.validate focusout.validate keyup.validate invalid-form.validate");
$.validator.unobtrusive.parse("form");
1
Benedikt Langer

動的コンテンツの場合、控えめな検証を以下のように更新し、Formが送信中に有効かどうかを確認する必要があります。

function UpdateUnobtrusiveValidations(idForm) {
    $(idForm).removeData("validator").removeData("unobtrusiveValidation");
    $.validator.unobtrusive.parse($(idForm));
};


$('#idDivPage').on('click', '#idSave', function (e) {
    e.preventDefault();
    if (!$('#idForm').valid()) {
        // Form is invalid … so return
        return false;
    }
    else {
        // post data to server using ajax call
        // update Unobtrusive Validations again
        UpdateUnobtrusiveValidations('#idForm');
    }
});
1

@Xhalentのコードスクリプトを自分のコードで見つけて、使用していなかったために削除しようとしていたので、このSO質問に至りました。

このコードは非常に簡潔でシンプルです。

jQuery.fn.unobtrusiveValidationForceBind = function () {
    //If you try to parse a form that is already parsed it won't update
    var $form = this
       .removeData("validator") /* added by the raw jquery.validate plugin */
            .removeData("unobtrusiveValidation");  /* added by the jquery     unobtrusive plugin */

    $form.bindUnobtrusiveValidation();
}

次に、このjQuery拡張機能を呼び出すには、セレクターを使用してフォームを取得します。

$('#formStart').unobtrusiveValidationForceBind();

ビオラ!

1
Brian Ogden

まず、呼び出しは検証ではなく.validatorにすべきだと思うので、フォームのidを渡す必要があります

$.validator.unobtrusive.parse("#id");
0
Chris Allmark

私はしばらくこれをいじり、解決策を廃棄し、後でやり直しました(暇なときに信じてください)。

このスレッドが最後に作成またはコメントされたので、jqueryの新しいバージョン(1.7.2を使用している)でこの動作が変更されたかどうかはわかりませんが、.parseElement(inputElement)がうまくいくことがわかりましたバリデーターが既にロードされているフォームに動的に作成された要素を追加します。これは、上記のコメントの1つで@jamesfm(2月15日)によって既に提案されていましたが、この作業に取り組んでいた最初の数回は見落としていました。それをより明確にするために別の回答として追加していますが、それは良い解決策であり、それほど多くのオーバーヘッドを必要としないからです。それは後続の回答で提起されたすべての問題に関連するわけではありませんが、元の質問の解決策になると思います。私が私の仕事を得た方法は次のとおりです。

//row & textarea created dynamically by an async ajax call further up in the code
var row = ...; //row reference from somewhere
var textarea = row.find("textarea");
textarea.val("[someValue]");

//add max length rule to the text area
textarea.rules('add', {
    maxlength: 2000
});
//parse the element to enable the validation on the dynamically added element
$.validator.unobtrusive.parseElement(textarea);
0
Ben