jquery.validate.unobtrusive no funciona con elementos inyectados dinámicos

99

Con el que estoy trabajando ASP.Net MVC3, la forma más fácil de usar la validación del cliente sería habilitar jquery.validate.unobtrusive. Todo funciona bien, para cosas que vienen directamente del servidor.

Pero cuando trato de inyectar algunas 'entradas' nuevas con javascript, y sabía que tenía que llamar $.validator.unobtrusive.parse()para volver a enlazar las validaciones. Pero aún así, todos esos campos inyectados dinámicos no están funcionando.

Peor aún, trato de enlazar manualmente usando jquery.validatey tampoco funciona. ¿Alguna idea?

X y Y
fuente
1
Si vino aquí desde Google, probablemente esté buscando la respuesta de @Sundara Prabu, ya que las otras que tienen una votación masiva son antiguas.
The Muffin Man

Respuestas:

65

Creé una extensión para la biblioteca jquery.validate.unobtrusive que resolvió este problema para mi situación; podría ser de interés.

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

Xhalent
fuente
Creo que debería votar tu respuesta como la correcta. Por cierto, ¿su biblioteca funciona con la última MVC RC? ¿O simplemente arreglaron eso?
xandy
1
Cuando use el código vinculado anteriormente, asegúrese de actualizarlo para incluir el código en los comentarios, de lo contrario, se puede romper. Específicamente, cambie las dos líneas de selección para que comillas dobles el id.
Ryan O'Neill
1
Finalmente pude hacer que esto funcionara para mi escenario después de algunas depuraciones. Parece que no debería pasar un selector de entrada, sino el padre de la entrada o el formulario, debido a la llamada a $.validator.unobtrusive.parse(). Además, parece que solo agrega nuevas reglas, pero no recoge actualizaciones de las reglas existentes.
Lambinator
5
Esta respuesta debe contener al menos los huesos del oso de la publicación del blog. Las respuestas de solo enlace generalmente están fuera de tema para SO
Liam
8
Si bien esta respuesta tiene más de 3 años, sería extremadamente útil si pudiera publicar las partes esenciales de la respuesta aquí, en este sitio, o su publicación corre el riesgo de ser eliminada. Consulte las Preguntas frecuentes donde menciona respuestas que son 'apenas más que un enlace '. Aún puede incluir el enlace si lo desea, pero solo como una "referencia". La respuesta debe mantenerse por sí sola sin necesidad del enlace.
Taryn
159

Probé el enfoque de Xhalent, pero desafortunadamente no funcionó para mí. El enfoque de Robin funcionó y no funcionó. Funcionó muy bien para elementos agregados dinámicamente, pero si intentara usar JQuery para eliminar todos los atributos de validación y los intervalos del DOM, la biblioteca de validación aún intentaría validarlos.

Sin embargo, si elimina los datos de "validación discreta" del formulario además de "validationData", funcionó como un encanto para agregar y eliminar dinámicamente elementos que desea validar o no validar.

$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");
viggity
fuente
2
Xhalent no funcionó para mí al principio tampoco, luego noté que se debe pasar al análisis un contenedor para los nuevos elementos, NO los elementos en sí mismos; la solución rápida sería pasar el formulario completo en lugar de los elementos, luego trabajado como un encanto.
Per Hornshøj-Schierbeck
1
¿Alguna idea de por qué dice validatorque no está definido? Tengo referencias de validación y validación. La validación funciona hasta que llamo a estos códigos
Shawn Mclean
4
Gracias. Funciona para contenido agregado a la página en vistas parciales ASP.MVC agregadas a través de una llamada AJAX.
Maksym Kozlenko
Gracias, esto ayudó. Pero me enfrento a un problema en el que estoy usando acordeones en la página y si el acordeón está colapsado, no activa las validaciones. ¿Cómo puedo arreglar esto? Sé que si hubiera optado por el complemento jquery validate normal en lugar de MVC3 discreto, tuve que decir$('#form').validate({ignore: ""})
parsh
1
Me funcionó en PHP. simplemente agregando esta información porque cada comentario apunta a .NET MVC. : P
finnTheHumin
42

De hecho, me gusta mucho la simplicidad de la solución @viggity y @Robins, así que la convertí en un pequeño complemento rápido:

(function ($) {

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

        $.validator.unobtrusive.parse(form);

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

Uso de ejemplo:

$("#DischargeOutcomeNumberOfVisits")
    .attr("data-val-range-min", this.checked ? "1" : "2")
    .updateValidation();
lambinator
fuente
reemplazar $ .validator.unobtrusive.parse ("#" + form.attr ("id")); con $ .validator.unobtrusive.parse (formulario);
Softlion
también puede eliminar de forma segura .first () ya que el más cercano devuelve solo 1 elemento.
Softlion
Bien
Funciona maravillosamente tanto para agregar como para eliminar atributos de valor de datos
Julian Dormon
33

Estoy teniendo el mismo problema. Descubrí que no es posible llamar a $ .validator.unobtrusive.parse () en el mismo formulario dos veces. Cuando se carga el formulario inicialmente desde el servidor, la biblioteca discreta analiza el formulario automáticamente. Cuando agrega un elemento de entrada dinámicamente al formulario y llama a $ .validator.unobtrusive.parse () nuevamente, no funcionará. Lo mismo ocurre con parseElement ().

La lib discreta llama al método validate del complemento jquery validate para establecer todas las reglas y mensajes. El problema es que, cuando se vuelve a llamar, el complemento no actualiza el nuevo conjunto de reglas que se le da.

Encontré una solución cruda: antes de llamar al método de análisis en la biblioteca discreta, desecho el validador de formularios:

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

Ahora, cuando el método de validación es llamado por la biblioteca discreta, todas las reglas y mensajes se recrean, incluidas las entradas agregadas dinámicamente.

Espero que esto ayude

Robin van der Knaap
fuente
Merece un +1: es una solución burda como usted mismo dijo, pero está bastante claro lo que hace y en qué estado se queda después
Per Hornshøj-Schierbeck
2
Del blog de Brad Wilson: "También puede llamar a la función jQuery.validator.unobtrusive.parseElement () para analizar un solo elemento HTML". ¿Alguna ayuda?
jamesfm
@Per Hornshøj-Schierbeck: @Robin van der Knaap: ¡¡He pasado las últimas 2-3 horas para resolver esto !! De todos modos, esto funcionó MARAVILLOSAMENTE. Sin embargo, crudo me hace sentir que no debería usarlo, ¿por qué no querría hacer esto?
KTF
2
La solución es un poco burda porque todos los validadores se eliminan y se reinstalan nuevamente, incluido el validador agregado dinámicamente. Sería mejor si solo se actualizara el validador agregado dinámicamente. @Xhalent proporciona una solución más limpia en su respuesta, pero básicamente la biblioteca discreta de MS debería actualizarse para este escenario.
Robin van der Knaap
9

Estoy usando MVC 4 y JQuery 1.8, parece que se necesita el siguiente código para permitir que Jquery valide el contenido inyectado dinámicamente a través de Ajax o Jquery en el DOM.

He creado una función modular que acepta el objeto Jquery del elemento recién agregado. Si ha clonado una nueva tabla con id tblContactsusando Jquery al hacer clic en un botón, incluya la función a continuación en su archivo 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.
}

y llámalo así:

fnValidateDynamicContent("#tblContacts")
Sundara Prabu
fuente
currform.validate (); en realidad debería ser currForm.validate (); (error de tipografía). Sin embargo, gracias por compartir, esto funcionó para mí
John Mc
1
@JohnMc corrigió el error tipográfico ahora
Sundara Prabu
Este es el único que funcionó para mí (mvc 4 y jquery 1.10)
The Muffin Man
4

¿Por qué no utilizar la función de reglas directamente desde el documento de validación de jquery? Me gusta esto:

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

Tomando de la solución de Xhalent marcada como respuesta anterior, la amplié un poco.

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

Básicamente, todavía funciona igual que la solución de Xhalent anterior, pero agregué la capacidad de eliminar reglas para los elementos que eliminas del dom. Entonces, cuando elimine elementos del Dom y desee que también se eliminen esas reglas de validación, llame a:

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

Encontré el script de código de @ Xhalent en mi código e iba a eliminarlo porque no lo estaba usando, lo que me llevó a esta pregunta SO.

Este código es bastante limpio y simple:

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

Luego, para llamar a esta extensión jQuery, simplemente use un selector para tomar su formulario:

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

¡Viola!

Brian Ogden
fuente
1

Probé la respuesta de Viggity y al principio todo pareció funcionar. Pero después de un tiempo me di cuenta de que la validación se vuelve dolorosamente lenta cuanto más dinámicamente agregué elementos. La razón fue que su solución no desvincula los controladores de eventos, sino que agrega nuevos cada vez. Entonces, si agrega 5 elementos, la validación se ejecuta 6 veces en lugar de solo una vez. Para solucionar este problema, debe desvincular los eventos además de las llamadas 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
fuente
1

En caso de contenido dinámico, debe actualizar las validaciones discretas como se muestra a continuación y verificar si Formes válido durante el envío.

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
fuente
0

He estado jugando con esto por un tiempo, descartando soluciones y volviéndolo a intentar más tarde (cuando tenía algo de tiempo libre, lo creas o no).

No estoy seguro de si este comportamiento habría cambiado en las versiones más recientes de jquery (estamos usando 1.7.2) desde que este hilo fue creado o comentado por última vez, pero encontré que .parseElement(inputElement)funciona bien cuando trato de agregar elementos creados dinámicamente a un formulario que ya tiene un validador cargado. Esto ya fue sugerido por @jamesfm (15 de febrero de 2011) en uno de los comentarios anteriores, pero lo pasé por alto las primeras veces que estuve trabajando en esto. Así que lo agrego como una respuesta separada para que sea más obvio y porque creo que es una buena solución y no requiere demasiada sobrecarga. Puede que no sea relevante para todas las cuestiones planteadas en las respuestas posteriores, pero creo que sería una solución a la pregunta original. Así es como hice funcionar el mío:

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

En primer lugar, creo que la llamada debe ser a .validator, no validar, entonces debe pasar la identificación del formulario

$.validator.unobtrusive.parse("#id");
Chris Allmark
fuente
Supongo que ha cargado los scripts jquery.validate y jquery.validate.unobtrusive y ha llamado a los métodos Html.EnableClientValidation () y Html.EnableUnobtrusiveJavaScript (). ¿Puede publicar una muestra de código para su página base y quizás el formulario cargado dinámicamente?
Chris Allmark
0

Si necesita agregar y eliminar cosas con la posibilidad de que ya se muestren algunos errores, esto es lo que vine. Se basa principalmente en diferentes ideas de esta página de preguntas. Utilizo el integrado en destroy()lugar de simplemente eliminar el atributo de datos para la validación de 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");
}

Lo llama antes de modificar dinámicamente las entradas en el formulario. Luego reinicializa la validación después.

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

Nota: Si algunas o todas las entradas se han validado y tienen errores, esos errores se restablecerán ... pero volverán correctamente en la próxima validación.

Yepeekai
fuente