¿Cómo usar ventanas emergentes de Twitter Bootstrap para notificaciones de validación de jQuery?

84

Puedo hacer que aparezcan popovers usando bootstrap con bastante facilidad, y también puedo hacer validaciones usando el complemento de validación de jQuery estándar o el motor de validación de jQuery , pero no puedo encontrar la manera de introducir uno en el otro.

Creo que lo que necesito es un gancho al que llame el validador cuando quiera mostrar una notificación, darle un cierre que pase el mensaje y el elemento de destino a un popover. Esto parece una especie de inyección de dependencia.

Todo bien en teoría, pero no puedo averiguar dónde está ese gancho, o incluso si existe uno en cualquiera de los motores de validación. Ambos parecen decididos a asumir la responsabilidad de mostrar notificaciones con todo tipo de opciones elaboradas para la ubicación, envoltorios, estilos cuando todo lo que busco son los tipos de error (ni siquiera necesito el texto del mensaje) y el elemento relacionado a. Encontré ganchos para todo el formulario, no para las notificaciones individuales.

Prefiero los sistemas de validación que usan clases para definir reglas, ya que funcionan bien con formularios creados dinámicamente.

¿Alguien tiene una solución o una mejor idea?

Sincronía
fuente

Respuestas:

21

Eche un vistazo a las opcioneshighlight y showErrors jQuery Validator , estas le permitirán enganchar sus propios aspectos destacados de errores personalizados que activan los popovers de Bootstrap.

Chris Fulstow
fuente
Eso es genial gracias. resaltar y no resaltar es lo que estaba buscando.
Sincronización
80

Este es un ejemplo práctico:

$('form').validate({
    errorClass:'error',
    validClass:'success',
    errorElement:'span',
    highlight: function (element, errorClass, validClass) { 
        $(element).parents("div[class='clearfix']").addClass(errorClass).removeClass(validClass); 
    }, 
    unhighlight: function (element, errorClass, validClass) { 
        $(element).parents(".error").removeClass(errorClass).addClass(validClass); 
    }
});

ingrese la descripción de la imagen aquí

Realmente no usa ventanas emergentes de arranque, pero se ve muy bien y es fácil de lograr.

ACTUALIZAR

Entonces, para tener la validación de popover, puede usar este código:

$("form").validate({
  rules : {
    test : {
      minlength: 3 ,
      required: true
    }
  },
  showErrors: function(errorMap, errorList) {
    $.each(this.successList, function(index, value) {
      return $(value).popover("hide");
    });
    return $.each(errorList, function(index, value) {
      var _popover;
      _popover = $(value.element).popover({
        trigger: "manual",
        placement: "top",
        content: value.message,
        template: "<div class=\"popover\"><div class=\"arrow\"></div><div class=\"popover-inner\"><div class=\"popover-content\"><p></p></div></div></div>"
      });
      // Bootstrap 3.x :      
      //_popover.data("bs.popover").options.content = value.message;
      // Bootstrap 2.x :
      _popover.data("popover").options.content = value.message;
      return $(value.element).popover("show");
    });
  }
});

Obtienes algo como esto:

ingrese la descripción de la imagen aquí

Echa un vistazo a jsFiddle .

Kenny Meyer
fuente
3
Voto a favor porque esto va en la dirección de lo que estaba buscando. :-) Vea mi respuesta para una variante.
namin
Qué hacer si es una forma de varias etapas
Taquiones
4
Solo una nota rápida de que con la última versión de Bootstrap ya no hay una clave .data ("popover"). Quizás para evitar colisiones han cambiado la clave a "bs.popover". Me tomó un tiempo descubrir por qué recibía un error indefinido . Así que ahora necesitarás usar _popover.data ("bs.popover"). Options.content = value.message; en el código anterior.
davidethell
¿Cómo puedo mostrar una ventana emergente en otro tipo de error que no sean los campos obligatorios? Quiero decir cómo puedo personalizarlo para que muestre errores solo en reglas específicas.
arjun
En realidad, hay un pequeño problema que también puede consultar fácilmente en jsFiddle. Si el campo no es obligatorio y se rompe alguna regla, aparece la ventana emergente, PERO si vacío el campo y me centro en otro campo, la ventana emergente todavía está allí. El primer bucle de SuccessList nunca se llama, por lo que el popover nunca está en un estado "hide" después de que se pone en un estado "show". Hay algo que podamos hacer al respecto ?
G4bri3l
9

Chris Fulstow lo tenía bien, pero todavía me tomó un tiempo, así que aquí está el código completo:

Esto muestra el popover en caso de error y oculta las etiquetas de error predeterminadas:

$('#login').validate({
  highlight: function(element, errClass) {
    $(element).popover('show');
  },
  unhighlight: function(element, errClass) {
    $(element).popover('hide');
  },
  errorPlacement: function(err, element) {
    err.hide();
  }
}).form();

Esto configura el popover. Lo único que necesita de esto es disparador: 'manual'

$('#password').popover({
  placement: 'below',
  offset: 20,
  trigger: 'manual'
});

El título y los atributos de contenido pasados ​​a popover no funcionaban, así que los especifiqué en línea en mi entrada de #password con data-content = 'Mínimo 5 caracteres' y data-original-title = 'Contraseña no válida'. También necesita rel = 'popover' en su formulario.

Esto funciona, pero la ventana emergente parpadea al anular la selección. ¿Alguna idea de como arreglarlo?

Varun Singh
fuente
6

Aquí hay un seguimiento de la excelente sugerencia de Varun Singh que evita el problema del "parpadeo" de la validación que intenta constantemente "mostrar" a pesar de que la ventana emergente ya está presente. Simplemente agregué una matriz de estados de error para capturar qué elementos muestran errores y cuáles no. ¡Funciona de maravilla!

var errorStates = [];

$('#LoginForm').validate({
    errorClass:'error',
    validClass:'success',
    errorElement:'span',
    highlight: function (element, errorClass) {
        if($.inArray(element, errorStates) == -1){
            errorStates[errorStates.length] = element;
            $(element).popover('show');
        }
    }, 
    unhighlight: function (element, errorClass, validClass) {
        if($.inArray(element, errorStates) != -1){
            this.errorStates = $.grep(errorStates, function(value) {
              return value != errorStates;
            });
            $(element).popover('hide');
        }
    },
    errorPlacement: function(err, element) {
        err.hide();
    }
});

$('#Login_unique_identifier').popover({
    placement: 'right',
    offset: 20,
    trigger: 'manual'
});

$('#Login_password').popover({
    placement: 'right',
    offset: 20,
    trigger: 'manual'
});
Jeffrey Gilbert
fuente
Esta fue la única respuesta en esta página que funcionó para mí. Es una pena que no se haya votado más.
alastairs
1
¿No significa esto que necesita definir un explícito popoverpara cada campo que desea validar? Si es así, eso es una locura .
g33kz0r
Para la mayoría de los casos de uso, esperaría que esto sea perfectamente aceptable. Si tiene una solución más óptima, no dude en agregarla :)
Jeffrey Gilbert
3

Prefiero cambiar el CSS de bootstrap. Acabo de agregar las clases de jQuery validate en el lugar correcto. error de validación de campo y error de validación de entrada

    form .clearfix.error > label, form .clearfix.error .help-block, form .clearfix.error .help-inline, .field-validation-error {
  color: #b94a48;
}
form .clearfix.error input, form .clearfix.error textarea, .input-validation-error {
  color: #b94a48;
  border-color: #ee5f5b;
}
form .clearfix.error input:focus, form .clearfix.error textarea:focus, .input-validation-error:focus {
  border-color: #e9322d;
  -webkit-box-shadow: 0 0 6px #f8b9b7;
  -moz-box-shadow: 0 0 6px #f8b9b7;
  box-shadow: 0 0 6px #f8b9b7;
}
Alberto Chvaicer
fuente
Este enfoque se ve mejor para mí :). Esto también es lo que estaba pensando
Freshblood
3

Así es como lo hice con Bootstrap 2.xy jQuery Validate 1.9

$('#form-register').validate({ errorElement: 'span', errorClass:'help-inline', highlight:    function (element, errorClass) {
        $(element).parent().parent().addClass('error');
    }, unhighlight: function (element, errorClass) {
        $(element).parent().parent().removeClass('error');
    }});
Jamie R Rytlewski
fuente
3

Por favor, eche un vistazo a lo siguiente:
- https://gist.github.com/3030983
Creo que es el más simple de todos.

EDITAR

Código del enlace:

$('form').validate({
    rules: {
        numero: {
            required: true
        },
        descricao: {
            minlength: 3,
            email: true,
            required: true
        }
    },

    showErrors: function (errorMap, errorList) {

        $.each(this.successList, function (index, value) {
            $(value).popover('hide');
        });


        $.each(errorList, function (index, value) {

            console.log(value.message);

            var _popover = $(value.element).popover({
                trigger: 'manual',
                placement: 'top',
                content: value.message,
                template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><div class="popover-content"><p></p></div></div></div>'
            });

            _popover.data('popover').options.content = value.message;

            $(value.element).popover('show');

        });

    }

});
Codemator
fuente
¡Muchas gracias por el aviso! Vea mi versión de Bootstrap pero con información sobre herramientas. En mi opinión, es más elegante que los popovers.
Adrian P.
3

¡Muchas gracias por el aviso! Aquí está mi versión de Bootstrap pero con información sobre herramientas. En mi opinión, es más elegante que los popovers. Sé que la pregunta era para popovers, así que por favor no vote en contra por esta razón. Quizás a alguien le gustará de esta manera. Me encanta cuando estoy buscando algo y encontré nuevas ideas en Stackoverflow. Nota: no es necesario marcar el formulario.

    $('#LoginForm').validate({
        rules: {
            password: {
                required: true,
                minlength: 6
            },

            email_address: {
                required: true,
                email: true
            }
        },
        messages: {
            password: {
                required: "Password is required",
                minlength: "Minimum length is 6 characters"
            },
            email_address: {
                required: "Email address is required",
                email: "Email address is not valid"
            }
        },  
        submitHandler: function(form) {
            form.submit();
        },

        showErrors: function (errorMap, errorList) {

            $.each(this.successList, function (index, value) {
                $('#'+value.id+'').tooltip('destroy');
            });


            $.each(errorList, function (index, value) {

                $('#'+value.element.id+'').attr('title',value.message).tooltip({
                    placement: 'bottom',
                    trigger: 'manual',
                    delay: { show: 500, hide: 5000 }
                }).tooltip('show');

            });

        }

    }); 
Adrian P.
fuente
1
Traté de usar su enfoque, pero estaba comenzando a obtener un error. y el problema es que si usa la interfaz de usuario de Jquery obtendrá un conflicto porque ambos usan información sobre herramientas. Sé que hay una solución para eso, pero solo quiero que otros usuarios sepan eso.
Richard Pérez
+1 para jQuery UI heads up! Tendrá que configurar su descarga personalizada (jQueryUI o Bootstrap) para NO incluir funciones de Tooltip JS. De todos modos, será un conflicto para cualquier información sobre herramientas si no lo hizo.
Adrian P.
hey, estaba tratando de usar su código con expresiones regulares y resulta que tengo un error en stackoverflow.com/questions/16087351/… . ¿Crees que puedes ayudar? :)
psharma
@psharma Nada que ver con bootstrap o tooltip. Su error es su declaración de reglas, ya que obtuvo una respuesta a su pregunta. el mensaje de error decía: ¡los términos no están definidos!
Adrian P.
Por alguna razón, esta es la única solución que funcionó para mí. ¡Gracias!
suchanoob
2

Así es como hice que sucediera. Pero implica hacer 2 cambios en el script de validación (obtuve el código para bootstrap 1.4 aquí y luego lo modifiqué - http://mihirchitnis.net/2012/01/customizing-error-messages-using-jquery-validate-plugin- para-twitter-bootstrap / )

Mi llamado a validar:

    $("#loginForm").validate({
  errorClass: "control-group error",
  validClass: "control-group success",
  errorElement: "span", // class='help-inline'
  highlight: function(element, errorClass, validClass) {
    if (element.type === 'radio') {
        this.findByName(element.name).parent("div").parent("div").removeClass(validClass).addClass(errorClass);
    } else {
        $(element).parent("div").parent("div").removeClass(validClass).addClass(errorClass);
    }
  },
  unhighlight: function(element, errorClass, validClass) {
    if (element.type === 'radio') {
        this.findByName(element.name).parent("div").parent("div").removeClass(errorClass).addClass(validClass);
    } else {
        $(element).parent("div").parent("div").removeClass(errorClass).addClass(validClass);
    }
  }
});

Luego, debe cambiar 2 cosas en jquery.validate.js
1. aplique esta solución: https://github.com/bsrykt/jquery-validation/commit/6c3f53ee00d8862bd4ee89bb627de5a53a7ed20a
2. Después de la línea 647 (en la función showLabel, cree la parte de la etiqueta ) después de la línea .addClass(this.settings.errorClass)agregar línea: .addClass("help-inline")
alguien tal vez pueda encontrar una manera de aplicar la segunda corrección en la función de validación, pero no he encontrado una manera, ya que se llama a showLabel después de resaltar.

Andrej Bergant
fuente
2

Esto es lo que puse en mi validación para cumplir con las pautas de Twitter Bootstrap. El mensaje de validación de error se coloca en a <span class=help-inline>y queremos resaltar el contenedor externo como erroro success:

errorClass:'help-inline',
errorElement:'span',
highlight: function (element, errorClass, validClass) {
$(element).parents("div.clearfix").addClass('error').removeClass('success');
},
unhighlight: function (element, errorClass, validClass) {
$(element).parents(".error").removeClass('error').addClass('success');
}
namin
fuente
2

Aquí hay una actualización de la excelente respuesta de Kenny Meyer anterior . Hubo un par de problemas que impidieron que funcionara para mí, que he abordado en este fragmento:

showErrors: function (errorMap, errorList) {
        $.each(this.successList, function (index, element) {
            return $(element).popover("destroy");
        });

        $.each(errorList, function (index, error) {
            var ele = $(error.element); //Instead of referencing the popover directly, I use the element that is the target for the popover

            ele.popover({
                    trigger: "manual",
                    placement: "top",
                    content: function(){ //use a function to assign the error message to content
                        return error.message
                    },
                    template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><div class="popover-content"><p></p></div></div></div>'
            });

            //bs.popover must be used, not just popover
            ele.data("bs.popover").options.content = error.message;

            return $(error.element).popover("show");
        });
    }
tofirius
fuente
Gracias por la iniciativa. El código ha cambiado mucho, como puedo ver :-)
Kenny Meyer
1

No estoy seguro de si esto es relevante para la discusión porque el cartel original pedía ganchos para mostrar / ocultar los popovers de arranque.

Estaba buscando una validación simple y los popovers no importaban. Una publicación relacionada y la primera en los resultados de búsqueda de Google ya se ha marcado como duplicado de esta pregunta. Así que tenía sentido mencionar este excelente JS jqValidation de @ ReactiveRaven, acertadamente llamado jqBootstrapValidation, que combina bien con Twitter Bootstrap. La configuración solo lleva unos minutos. Descárgalo aquí .

Espero que esto agregue valor.

uchamp
fuente
1

tl; dr evite la necesidad de enumerar elementos emergentes explícitos mediante el uso de un mapa hash para almacenar los identificadores de los elementos y la creación de elementos emergentes sobre la marcha (combinación de los enfoques de Jeffrey Gilbert y Kenny Meyer).

Aquí está mi opinión, que soluciona el problema de parpadeo mencionado por otros, pero a diferencia de la respuesta de @Jeffrey Gilbert, no usa una lista ( errorStates) sino que usa un mapa de error . Mapas hash FTW. Creo que recuerdo haber leído en alguna parte que todos los problemas en CS se pueden resolver con un mapa hash :)

var err_map = new Object();     // <--- n.b.
$("form#set_draws").validate({
  rules: {
    myinput: { required: true, number: true },
  },
  showErrors: function(errorMap, errorList) {
    $.each(this.successList, function(index, value) {
      if (value.id in err_map)
      {
        var k = err_map[value.id];
        delete err_map[value.id]; // so validation can transition between valid/invalid states
        k.popover("hide");
      }
    });
    return $.each(errorList, function(index, value) {
      var element = $(value.element);
      if( ! (value.element.id in err_map) ) {
        var _popover = element.popover({
          trigger: "manual",
                 placement: "top",
                 content: value.message,
                 template: "<div class=\"popover\"><div class=\"arrow\"></div><div class=\"popover-inner\"><div class=\"popover-content\"><p></p></div></div></div>"
        });
        _popover.data("popover").options.content = value.message;
          err_map[value.element.id] = _popover;
        return err_map[value.element.id].popover("show");
      }
    });
  }
});

Gracias a todos los que publicaron ideas sobre esto.

g33kz0r
fuente
0

Si usa el código Kenny Meyer anterior para ventanas emergentes, tenga en cuenta que las reglas que verifican el contenido de un campo pero no son necesarias, como una URL válida, harán que la ventana emergente no desaparezca al borrar el campo. Vea abajo onkeyup para la solución. Si alguien tiene una mejor solución, publique.

onkeyup: function(element, event) {
            if($(element).valid())  {
                return $(element).popover("hide");
            }
        }
monzón
fuente