jquery.validate.unobtrusive tidak berfungsi dengan elemen injeksi dinamis

99

Saya sedang bekerja ASP.Net MVC3, cara yang lebih mudah untuk menggunakan validasi klien adalah dengan mengaktifkan jquery.validate.unobtrusive. Semuanya berfungsi dengan baik, untuk hal-hal yang langsung dari server.

Tetapi ketika saya mencoba untuk memasukkan beberapa 'input' baru dengan javascript, dan saya tahu bahwa saya perlu memanggil $.validator.unobtrusive.parse()untuk me-rebind validasi. Tapi tetap saja, semua bidang injeksi dinamis tersebut tidak berfungsi.

Lebih buruk lagi, saya mencoba mengikat secara manual jquery.validatedan tidak berhasil juga. Ada pemikiran?

xandy
sumber
1
Jika Anda datang ke sini dari google, Anda mungkin mencari jawaban @Sundara Prabu karena yang lain yang diberi suara positif secara besar-besaran sudah lama.
The Muffin Man

Jawaban:

65

Saya telah membuat ekstensi untuk pustaka jquery.validate.unobtrusive yang memecahkan masalah ini untuk situasi saya - mungkin menarik.

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

Xhalent
sumber
Saya pikir saya harus memilih jawaban Anda sebagai yang benar. BTW, apakah perpustakaan Anda berfungsi dengan MVC RC terbaru? atau mereka baru saja memperbaikinya?
xandy
1
Saat menggunakan kode yang ditautkan di atas, pastikan Anda memperbaruinya untuk memasukkan kode dalam komentar jika tidak maka dapat rusak. Secara khusus, ubah dua baris pemilih untuk mengutip ganda id.
Ryan O'Neill
1
Akhirnya bisa mendapatkan ini berfungsi untuk skenario saya setelah beberapa debugging. Tampaknya tidak boleh lewat di pemilih input, tetapi input induk atau formulir, karena panggilan ke $.validator.unobtrusive.parse(). Selain itu, tampaknya hanya menambahkan aturan baru, tetapi tidak mengambil pembaruan untuk aturan yang sudah ada?
lambinator
5
Jawaban ini setidaknya harus mengandung tulang punggung posting blog. Tautan saja jawaban umumnya di luar topik untuk SO
Liam
8
Meskipun jawaban ini berusia 3+ tahun, akan sangat membantu jika Anda dapat memposting bagian penting dari jawaban di sini, di situs ini, atau posting Anda berisiko dihapus. Lihat FAQ yang menyebutkan jawaban yang 'hampir tidak lebih dari sebuah tautan '. Anda masih dapat menyertakan tautan jika Anda mau, tetapi hanya sebagai 'referensi'. Jawabannya harus berdiri sendiri tanpa memerlukan tautan.
Taryn
159

Saya mencoba pendekatan Xhalent tetapi sayangnya itu tidak berhasil untuk saya. Pendekatan Robin berhasil dan tidak berhasil. Ini berfungsi dengan baik untuk elemen yang ditambahkan secara dinamis, tetapi jika Anda mencoba menggunakan JQuery untuk menghapus semua atribut dan span validasi dari DOM, pustaka validasi masih akan mencoba memvalidasinya.

Namun, jika Anda menghapus data "unobtrusiveValidation" formulir selain "validationData", ini berfungsi seperti pesona untuk secara dinamis menambahkan dan menghapus elemen yang Anda ingin divalidasi atau tidak divalidasi.

$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");
viggity
sumber
2
Xhalent juga tidak berfungsi untuk saya pada awalnya, kemudian saya perhatikan bahwa parse harus melewati wadah untuk elemen baru, BUKAN elemen itu sendiri - perbaikan cepat akan meneruskan seluruh formulir alih-alih elemen - lalu itu bekerja seperti pesona.
Per Hornshøj-Schierbeck
1
tahu mengapa dikatakan validatortidak ditentukan? Saya memiliki referensi validasi dan validation.unobtrusive. Validasi berfungsi sampai saya memanggil kode ini
Shawn Mclean
4
Terima kasih. Ia bekerja untuk konten yang ditambahkan ke halaman dalam tampilan parsial ASP.MVC ditambahkan melalui panggilan AJAX.
Maksym Kozlenko
Terima kasih ini membantu. Tapi saya menghadapi masalah di mana saya menggunakan akordeon pada halaman dan jika akordeon diciutkan, validasi tidak akan diaktifkan. Bagaimana cara memperbaikinya? Saya tahu jika saya telah menggunakan plugin validasi jquery normal daripada MVC3 yang tidak mengganggu, saya harus mengatakan$('#form').validate({ignore: ""})
parsh
1
Ini berhasil untuk saya di PHP. hanya menambahkan info ini karena setiap komentar mengarah ke .NET MVC. : P
finnTheHumin
42

Saya sebenarnya sangat menyukai kesederhanaan solusi @viggity dan @Robins, jadi saya mengubahnya menjadi plugin kecil yang cepat:

(function ($) {

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

        $.validator.unobtrusive.parse(form);

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

Contoh penggunaan:

$("#DischargeOutcomeNumberOfVisits")
    .attr("data-val-range-min", this.checked ? "1" : "2")
    .updateValidation();
lambinator
sumber
ganti $ .validator.unobtrusive.parse ("#" + form.attr ("id")); dengan $ .validator.unobtrusive.parse (form);
Softlion
Anda juga bisa menghapus .first () dengan aman karena yang terdekat hanya mengembalikan 1 elemen.
Softlion
Bagus, saya suka pendekatan sederhana ini
nixon
Bekerja dengan baik untuk menambahkan dan menghapus atribut data-val
Julian Dormon
33

Saya mempunyai masalah yang sama. Saya menemukan bahwa tidak mungkin memanggil $ .validator.unobtrusive.parse () pada formulir yang sama dua kali. Saat memuat formulir awalnya dari server, formulir diurai secara otomatis oleh pustaka yang tidak mengganggu. Saat Anda menambahkan elemen input secara dinamis ke formulir dan memanggil $ .validator.unobtrusive.parse () lagi, itu tidak akan berfungsi. Hal yang sama berlaku untuk parseElement ().

Lib yang tidak mengganggu memanggil metode validasi dari plugin jquery validate untuk menyetel semua aturan dan pesan. Masalahnya adalah, ketika dipanggil lagi, plugin tidak memperbarui sekumpulan aturan baru yang diberikan.

Saya menemukan satu solusi kasar: Sebelum memanggil metode parse pada lib yang tidak mengganggu, saya membuang validator formulir:

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

Sekarang, ketika metode validasi dipanggil oleh lib yang tidak mengganggu, semua aturan dan pesan dibuat ulang termasuk input yang ditambahkan secara dinamis.

Semoga ini membantu

Robin van der Knaap
sumber
Pantas mendapatkan +1 - ini adalah solusi kasar seperti yang Anda katakan sendiri, tetapi cukup jelas apa yang dilakukannya dan apa yang tersisa setelahnya
Per Hornshøj-Schierbeck
2
Dari blog Brad Wilsons: "Anda juga dapat memanggil fungsi jQuery.validator.unobtrusive.parseElement () untuk mengurai satu elemen HTML." Ada bantuan?
jamesfm
@ Per Hornshøj-Schierbeck: @Robin van der Knaap: Saya telah menghabiskan 2-3 jam terakhir untuk mencari tahu !! Pokoknya- ini bekerja dengan luar biasa. Minyak mentah membuat saya merasa saya seharusnya tidak menggunakannya- mengapa saya tidak ingin melakukan ini?
KTF
2
Solusinya agak kasar karena semua validator dihapus dan dipulihkan kembali, termasuk validator yang ditambahkan secara dinamis. Akan lebih baik jika hanya validator yang ditambahkan secara dinamis yang diperbarui. @Xhalent memberikan solusi yang lebih bersih dalam jawabannya, tetapi pada dasarnya pustaka yang tidak mengganggu dari MS harus diperbarui untuk skenario ini.
Robin van der Knaap
9

Saya menggunakan MVC 4 dan JQuery 1.8, sepertinya potongan kode berikut diperlukan untuk mengaktifkan Jquery untuk memvalidasi konten yang disuntikkan secara dinamis melalui Ajax, atau Jquery ke DOM.

Saya telah membuat fungsi modular yang menerima objek Jquery dari elemen yang baru ditambahkan. Jika Anda telah mengkloning tabel baru dengan id tblContactsmenggunakan Jquery dengan mengklik tombol, maka sertakan fungsi di bawah ini di file js Anda

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.
}

dan menyebutnya seperti ini:

fnValidateDynamicContent("#tblContacts")
Sundara Prabu
sumber
currform.validate (); seharusnya benar-benar menjadi currForm.validate (); (salah ketik). Terima kasih telah berbagi, ini berhasil untuk saya
John Mc
1
@JohnMc memperbaiki kesalahan ketik sekarang
Sundara Prabu
Ini adalah satu-satunya yang berhasil untuk saya (mvc 4 dan jquery 1.10)
The Muffin Man
4

Mengapa tidak menggunakan fungsi rules langsung dari jquery validation doc. Seperti ini:

$('#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');
zhangfx
sumber
2

Mengambil dari solusi Xhalent yang ditandai sebagai jawaban di atas, saya memperluasnya sedikit.

$.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];
            }
        }
    }
}

Jadi pada dasarnya ini masih berfungsi sama dengan solusi Xhalent di atas tetapi saya menambahkan kemampuan untuk menghapus aturan untuk elemen yang Anda hapus dari dom. Jadi, ketika Anda menghapus elemen dari Dom dan Anda ingin aturan validasi tersebut dihapus juga, panggil:

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

Saya menemukan skrip kode @ Xhalent dalam kode saya dan akan menghapusnya karena saya tidak menggunakannya, yang membawa saya ke pertanyaan SO ini.

Kode ini cukup bersih dan sederhana:

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();
}

Kemudian, untuk memanggil ekstensi jQuery ini, cukup gunakan selektor untuk mengambil formulir Anda:

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

Biola!

Brian Ogden
sumber
1

Saya mencoba jawaban viggity dan pada awalnya semuanya tampak berhasil. Tetapi setelah beberapa saat saya perhatikan bahwa validasi menjadi sangat lambat karena item yang lebih dinamis yang saya tambahkan. Alasannya adalah solusinya tidak melepaskan penangan acara, tetapi menambahkan yang baru setiap saat. Jadi jika Anda menambahkan 5 item validasi dijalankan 6 kali, bukan hanya sekali. Untuk mengatasinya, Anda harus melepaskan peristiwa tersebut sebagai tambahan ke panggilan removeData.

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

Dalam kasus konten dinamis Anda perlu memperbarui Validasi Tidak Mencolok seperti di bawah ini dan memeriksa apakah Formvalid saat mengirimkan.

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');
    }
});
Jagdeesh Motegowda
sumber
0

Saya telah mengotak-atik ini untuk sementara waktu, membuang solusi dan mencoba lagi nanti (ketika saya punya waktu luang, percaya atau tidak).

Saya tidak yakin apakah perilaku ini akan berubah di versi jquery yang lebih baru (kami menggunakan 1.7.2) sejak utas ini dibuat atau dikomentari terakhir, tetapi saya menemukan itu .parseElement(inputElement)berfungsi dengan baik ketika saya mencoba menambahkan elemen yang dibuat secara dinamis ke formulir yang sudah memuat validator. Ini sudah disarankan oleh @jamesfm (15 Feb '11) di salah satu komentar di atas, tetapi saya mengabaikannya beberapa kali pertama kali saya mengerjakan ini. Jadi saya menambahkannya sebagai jawaban terpisah untuk membuatnya lebih jelas dan karena menurut saya ini adalah solusi yang baik dan tidak memerlukan banyak biaya tambahan. Ini mungkin tidak relevan untuk semua masalah yang diangkat dalam jawaban berikutnya, tetapi saya pikir ini akan menjadi solusi untuk pertanyaan asli. Inilah cara saya membuat milik saya bekerja:

//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);
Ben
sumber
0

Pertama, menurut saya panggilannya harus ke .validator, bukan validasi maka Anda harus memasukkan id formulir

$.validator.unobtrusive.parse("#id");
Chris Allmark
sumber
Saya berasumsi Anda telah memuat skrip jquery.validate & jquery.validate.unobtrusive dan memanggil metode Html.EnableClientValidation () dan Html.EnableUnobtrusiveJavaScript ()? Dapatkah Anda memposting contoh kode untuk halaman dasar Anda dan mungkin formulir yang dimuat secara dinamis?
Chris Allmark
0

Jika Anda perlu menambah dan menghapus sesuatu dengan kemungkinan beberapa kesalahan sudah ditampilkan, inilah yang saya berikan. Ini terutama didasarkan pada ide-ide yang berbeda di halaman pertanyaan ini. Saya menggunakan bawaan destroy()alih-alih hanya menghapus atribut data untuk validasi JQuery.

function resetValidator($form: JQuery) {
    $form.validate().destroy();

    //reset unobtrusive validation summary, if it exists
    $form.find("[data-valmsg-summary=true]")
        .removeClass("validation-summary-errors")
        .addClass("validation-summary-valid")
        .find("ul").empty();

    //reset unobtrusive field level, if it exists
    $form.find("[data-valmsg-replace]")
        .removeClass("field-validation-error")
        .addClass("field-validation-valid")
        .empty();

    $form.removeData("unobtrusiveValidation");
}

Anda menyebutnya sebelum secara dinamis mengubah masukan dalam formulir. Anda kemudian menginisialisasi ulang validasi setelahnya.

resetValidator($form);
//add or remove inputs here ...
$.validator.unobtrusive.parse($form);

Catatan: Jika beberapa atau semua input telah divalidasi dan memiliki kesalahan, kesalahan tersebut akan diatur ulang ... tetapi mereka akan kembali dengan benar pada validasi berikutnya.

Yepeekai
sumber