jquery.validate.unobtrusive non funziona con elementi dinamici iniettati


99

Sto lavorando con ASP.Net MVC3, il modo più semplice per utilizzare la convalida del client sarebbe abilitare il jquery.validate.unobtrusive. Tutto funziona bene, per le cose che sono corrette dal server.

Ma quando provo a iniettare nuovi "input" con javascript, e sapevo che ho bisogno di chiamare $.validator.unobtrusive.parse()per riassociare le convalide. Tuttavia, tutti quei campi dinamici iniettati non funzionano.

Ancora peggio, provo a legare manualmente usando jquery.validatee non funziona neanche. qualche idea?


1
Se sei venuto qui da Google probabilmente stai cercando la risposta di @Sundara Prabu poiché gli altri che sono stati votati in modo massiccio sono vecchi.
The Muffin Man

Risposte:


65

Ho creato un'estensione per la libreria jquery.validate.unobtrusive che ha risolto questo problema per la mia situazione - potrebbe essere di interesse.

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


Penso che dovrei votare la tua risposta come quella giusta. A proposito, la tua libreria funziona con l'ultima MVC RC? o l'hanno appena risolto?
xandy

1
Quando si utilizza il codice collegato sopra, assicurarsi di aggiornarlo per includere il codice nei commenti altrimenti potrebbe interrompersi. In particolare, modificare le due righe del selettore per virgolette due volte l'id.
Ryan O'Neill

1
Finalmente sono riuscito a farlo funzionare per il mio scenario dopo un po 'di debug. Sembra che non dovrebbe passare un selettore di input, ma il genitore dell'input o il form, a causa della chiamata a $.validator.unobtrusive.parse(). Inoltre, sembra che aggiunga solo nuove regole, ma non raccolga aggiornamenti alle regole esistenti?
lambinator

5
Questa risposta dovrebbe contenere almeno le ossa d'orso del post del blog. Le risposte solo ai link sono generalmente fuori tema per SO
Liam

8
Sebbene questa risposta abbia più di 3 anni, sarebbe estremamente utile se potessi pubblicare le parti essenziali della risposta qui, su questo sito, altrimenti il ​​tuo post rischia di essere cancellato Vedi le FAQ dove menziona risposte che sono 'poco più di un link '. Puoi comunque includere il link se lo desideri, ma solo come "riferimento". La risposta dovrebbe stare da sola senza bisogno del collegamento.
Taryn

159

Ho provato l'approccio di Xhalent ma sfortunatamente non ha funzionato per me. L'approccio di Robin ha funzionato e non ha funzionato. Ha funzionato alla grande per gli elementi aggiunti dinamicamente, ma se si provava a utilizzare JQuery per rimuovere tutti gli attributi di convalida e gli intervalli dal DOM, la libreria di convalida avrebbe comunque provato a convalidarli.

Tuttavia, se rimuovi i dati "unobtrusiveValidation" del modulo oltre a "validationData", ha funzionato come un fascino per aggiungere e rimuovere dinamicamente gli elementi che desideri convalidare o non convalidare.

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

2
Anche Xhalent all'inizio non ha funzionato per me, poi ho notato che l'analisi dovrebbe essere passata a un contenitore per i nuovi elementi, NON agli elementi stessi - la soluzione rapida sarebbe passare l'intero modulo invece degli elementi - quindi ha funzionato come un fascino.
Per Hornshøj-Schierbeck

1
qualche idea del perché si dice validatornon è definito? Ho sia validation che validation.unobtrusive referenziate. La convalida funziona finché non chiamo questo codice
Shawn Mclean

4
Grazie. Funziona per il contenuto aggiunto alla pagina nelle visualizzazioni parziali ASP.MVC aggiunte tramite chiamata AJAX.
Maksym Kozlenko

Grazie questo ha aiutato. Ma sto affrontando un problema in cui sto usando le fisarmoniche sulla pagina e se la fisarmonica è compressa, non attiva le convalide. Come posso risolvere questo problema? So che se avessi scelto il normale plug-in di convalida jquery invece di MVC3 discreto, dovevo dire$('#form').validate({ignore: ""})
parsh

1
Ha funzionato per me in PHP. aggiungendo semplicemente queste informazioni perché ogni commento punta a .NET MVC. : P
finnTheHumin

42

In realtà mi piace molto la semplicità delle soluzioni @viggity e @Robins, quindi l'ho trasformata in un piccolo plug-in veloce:

(function ($) {

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

        $.validator.unobtrusive.parse(form);

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

Utilizzo di esempio:

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

sostituire $ .validator.unobtrusive.parse ("#" + form.attr ("id")); con $ .validator.unobtrusive.parse (modulo);
Softlion

puoi anche rimuovere in sicurezza .first () poiché il valore più vicino restituisce solo 1 elemento.
Softlion

Bello, mi piace questo semplice approccio
nixon

Funziona magnificamente sia per l'aggiunta che per la rimozione di attributi data-val
Julian Dormon

33

Ho lo stesso problema. Ho scoperto che non è possibile chiamare $ .validator.unobtrusive.parse () nella stessa forma due volte. Quando si carica il modulo inizialmente dal server, il modulo viene analizzato automaticamente dalla libreria non invadente. Quando aggiungi un elemento di input dinamicamente al form e chiami di nuovo $ .validator.unobtrusive.parse (), non funzionerà. Lo stesso vale per parseElement ().

La libreria discreta chiama il metodo validate del plugin validate jquery per impostare tutte le regole ei messaggi. Il problema è che, quando viene chiamato di nuovo, il plug-in non aggiorna il nuovo set di regole fornito.

Ho trovato una soluzione grossolana: prima di chiamare il metodo di analisi sulla libreria discreta, ho buttato via il validatore del modulo:

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

Ora, quando il metodo validate viene chiamato dalla libreria discreta, tutte le regole ei messaggi vengono ricreati, inclusi gli input aggiunti dinamicamente.

Spero che questo ti aiuti


Merita un +1 - è una soluzione rozza come hai detto tu stesso, ma è abbastanza chiaro cosa fa e in quale stato ti trovi in ​​seguito
Per Hornshøj-Schierbeck

2
Dal blog di Brad Wilsons: "Puoi anche chiamare la funzione jQuery.validator.unobtrusive.parseElement () per analizzare un singolo elemento HTML." Qualsiasi aiuto?
jamesfm

@Per Hornshøj-Schierbeck: @Robin van der Knaap: ho passato le ultime 2-3 ore a capirlo !! Comunque, questo ha funzionato MERAVIGLIOSAMENTE. Il grezzo mi fa sentire che non dovrei usarlo però, perché non dovrei farlo?
KTF

2
La soluzione è un po 'rozza perché tutti i validatori vengono rimossi e reintegrati di nuovo, incluso il validatore aggiunto dinamicamente. Sarebbe meglio se fosse aggiornato solo il validatore aggiunto dinamicamente. @Xhalent fornisce una soluzione più pulita nella sua risposta, ma fondamentalmente la libreria discreta di MS dovrebbe essere aggiornata per questo scenario.
Robin van der Knaap

9

Sto usando MVC 4 e JQuery 1.8, sembra che la seguente parte di codice sia necessaria per abilitare Jquery alla convalida del contenuto iniettato dinamicamente tramite Ajax o Jquery nel DOM.

Ho realizzato una funzione modulare che accetta l'oggetto Jquery dell'elemento appena aggiunto. Se hai clonato una nuova tabella con ID tblContactsusando Jquery al clic di un pulsante, includi la funzione seguente nel tuo file 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.
}

e chiamalo così:

fnValidateDynamicContent("#tblContacts")

currform.validate (); dovrebbe effettivamente essere currForm.validate (); (errore di battitura). Grazie per la condivisione però, questo ha funzionato per me
John Mc

1
@JohnMc ha corretto l'errore di battitura ora
Sundara Prabu

Questo è l'unico che ha funzionato per me (mvc 4 e jquery 1.10)
The Muffin Man

4

Perché non utilizzare la funzione regole direttamente dal documento di convalida jquery. Come questo:

$('#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

Prendendo dalla soluzione di Xhalent contrassegnata come risposta sopra, l'ho ampliata un po '.

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

Quindi fondamentalmente funziona ancora come la soluzione di Xhalent sopra, ma ho aggiunto la possibilità di rimuovere le regole per gli elementi che rimuovi dal dom. Quindi, quando rimuovi elementi dal Dom e desideri rimuovere anche quelle regole di convalida, chiama:

$.validator.unobtrusive.unparseContent('input.something');

1

Ho trovato lo script di codice di @ Xhalent nel mio codice e stavo per eliminarlo perché non lo stavo usando, il che mi ha portato a questa domanda SO.

Questo codice è abbastanza pulito e semplice:

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

Quindi, per chiamare questa estensione jQuery, usa un selettore per afferrare il tuo modulo:

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

Viola!


1

Ho provato la risposta di viggity e all'inizio tutto sembrava funzionare. Ma dopo un po 'ho notato che la convalida diventa dolorosamente lenta gli elementi che ho aggiunto in modo più dinamico. Il motivo era che la sua soluzione non svincola i gestori di eventi, ma ne aggiunge di nuovi ogni volta. Quindi, se aggiungi 5 elementi, la convalida viene eseguita 6 volte invece di una sola. Per risolvere questo problema è necessario svincolare gli eventi in aggiunta alle chiamate 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

In caso di contenuti dinamici è necessario aggiornare le convalide discrete come di seguito e controllare se Formè valido durante l'invio.

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

0

Sto giocherellando con questo per un po ', scartando soluzioni e riprovando più tardi (quando avevo un po' di tempo libero, che ci crediate o no).

Non sono sicuro se questo comportamento sarebbe cambiato nelle versioni più recenti di jquery (stiamo usando 1.7.2) poiché questo thread è stato creato o commentato per ultimo, ma ho scoperto che .parseElement(inputElement)funziona bene quando provo ad aggiungere elementi creati dinamicamente a un modulo che ha già un validatore caricato. Questo è stato già suggerito da @jamesfm (15 febbraio 11) in uno dei commenti sopra, ma l'ho trascurato le prime volte che ci stavo lavorando. Quindi lo aggiungo come risposta separata per renderlo più ovvio e perché penso che sia una buona soluzione e non richieda così tanto overhead. Potrebbe non essere pertinente per tutte le questioni sollevate nelle risposte successive, ma penso che sarebbe una soluzione alla domanda originale. Ecco come ho fatto funzionare il mio:

//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

In primo luogo, penso che la chiamata dovrebbe essere a .validator, non convalidare, quindi devi passare l'id del modulo

$.validator.unobtrusive.parse("#id");

Presumo che tu abbia caricato entrambi gli script jquery.validate e jquery.validate.unobtrusive e abbia chiamato i metodi Html.EnableClientValidation () e Html.EnableUnobtrusiveJavaScript ()? Puoi pubblicare un esempio di codice per la tua pagina di base e il modulo caricato dinamicamente forse?
Chris Allmark

0

Se è necessario aggiungere e rimuovere elementi con la possibilità che alcuni errori siano già visualizzati, questo è ciò che ho fornito. Si basa principalmente su idee diverse in questa pagina delle domande. Uso il built-in destroy()invece di rimuovere semplicemente l'attributo data per JQuery validate.

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

Lo chiami prima di modificare dinamicamente gli input nel modulo. Successivamente si reinizializza la convalida.

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

Nota: se alcuni o tutti gli input sono stati convalidati e contengono errori, tali errori verranno ripristinati ... ma torneranno correttamente alla convalida successiva.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.