Jak używać wyskakujących okienek Twitter Bootstrap do powiadomień walidacyjnych jQuery?

84

Mogę łatwo sprawić, by popover pojawiał się przy użyciu bootstrap , a także mogę przeprowadzać walidacje za pomocą standardowej wtyczki walidacji jQuery lub silnika walidacji jQuery , ale nie mogę dowiedzieć się, jak wprowadzić jeden do drugiego.

Myślę, że potrzebuję jakiegoś haka, który jest wywoływany przez walidator, gdy chce wyświetlić powiadomienie, nadać mu zamknięcie, które przekazuje wiadomość i element docelowy do popover. Wydaje się, że jest to rodzaj zastrzyku zależności.

Wszystko fajnie w teorii, ale po prostu nie mogę dowiedzieć się, gdzie jest ten hak, a nawet czy istnieje w którymkolwiek z silników walidacji. Obaj wydają się być zdecydowani wziąć odpowiedzialność za wyświetlanie powiadomień z wszelkiego rodzaju wyszukanymi opcjami umieszczania, opakowaniami, stylami, gdy jedyne, czego szukam, to typ (y) błędu (niekoniecznie potrzebuję nawet tekstu wiadomości) i element, do którego się odnosi do. Znalazłem haczyki dla całego formularza, a nie dla poszczególnych powiadomień.

O wiele bardziej wolę systemy walidacji, które używają klas do definiowania reguł, ponieważ dobrze bawią się dynamicznie tworzonymi formularzami.

Czy ktoś ma rozwiązanie lub lepszy pomysł?

Synchro
źródło

Odpowiedzi:

21

Zapoznaj się z opcjamihighlight i showErrors jQuery Validator , które pozwolą Ci podpiąć własne niestandardowe podświetlenia błędów, które wyzwalają wyskakujące okienka Bootstrap.

Chris Fulstow
źródło
To jest świetne, dziękuję. Highlight i unhighlight są tym, czego szukałem.
Synchro
80

Oto praktyczny przykład:

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

wprowadź opis obrazu tutaj

Tak naprawdę nie używa wyskakujących okienek bootstrap, ale wygląda naprawdę ładnie i jest łatwy do osiągnięcia.

AKTUALIZACJA

Aby mieć walidację popover, możesz użyć tego kodu:

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

Otrzymasz coś takiego:

wprowadź opis obrazu tutaj

Sprawdź jsFiddle .

Kenny Meyer
źródło
3
Głosowano za, ponieważ jest to w kierunku tego, czego szukałem. :-) Zobacz moją odpowiedź na wariant.
namin
Co zrobić, jeśli jest to forma wieloetapowa
Tachyons
4
Krótka uwaga, że ​​w najnowszej wersji Bootstrap nie ma już klucza .data („popover”). Być może, aby uniknąć kolizji, zmienili klucz na „bs.popover”. Zajęło mi trochę czasu, zanim zrozumiałem, dlaczego otrzymuję nieokreślony błąd. Więc teraz musisz użyć _popover.data ("bs.popover"). Options.content = value.message; w powyższym kodzie.
davidethell
Jak mogę wyświetlić wyskakujące okienko w przypadku innego typu błędu niż pola wymagane. Chodzi mi o to, jak mogę go dostosować, aby wyświetlał błąd tylko na określonych zasadach.
arjun
W rzeczywistości jest mały problem, który możesz łatwo sprawdzić również w jsFiddle. Jeśli pole nie jest wymagane, a jakaś reguła jest zepsuta, pojawia się okienko popover, ALE jeśli opróżnię to pole i skupię się na innym polu, okno podręczne nadal tam jest. Pierwsza pętla na liście sukcesów nigdy nie jest wywoływana, więc popover nigdy nie jest w stanie „ukrywania” po przejściu w stan „pokazu”. Czy jest coś, co możemy z tym zrobić?
G4bri3l
9

Chris Fulstow miał rację, ale zajęło mi to trochę czasu, więc oto cały kod:

Spowoduje to wyświetlenie okna podręcznego w przypadku błędu i ukrycie domyślnych etykiet błędów:

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

Spowoduje to skonfigurowanie popover. Jedyne, czego potrzebujesz, to wyzwalacz: „ręczny”

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

Atrybuty tytułu i treści przekazane do popover nie działały, więc określiłem je w moim wpisie #password z danymi = „Minimum 5 znaków” i data-original-title = „Nieprawidłowe hasło”. W swoim formularzu potrzebujesz również rel = 'popover'.

To działa, ale popover miga po cofnięciu wyboru. Masz jakiś pomysł, jak to naprawić?

Varun Singh
źródło
6

Oto kontynuacja doskonałej sugestii Varun Singha, która zapobiega problemowi „migotania” podczas weryfikacji, która nieustannie próbuje „pokazać”, mimo że wyskakujące okienko jest już obecne. Po prostu dodałem tablicę stanów błędów, aby wychwycić, które elementy pokazują błędy, a które nie. Działa jak marzenie!

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
źródło
To była jedyna odpowiedź na tej stronie, która mi pomogła. Szkoda, że ​​nie został bardziej oceniony.
alastairs
1
Czy to nie oznacza, że ​​musisz zdefiniować jawne popoverdla każdego pola, które chcesz zweryfikować? Jeśli tak, to szaleństwo .
g33kz0r
Spodziewałbym się, że w większości przypadków jest to całkowicie akceptowalne. Jeśli masz bardziej optymalne rozwiązanie, możesz je dodać :)
Jeffrey Gilbert
3

Wolę zmienić CSS bootstrapa. Właśnie dodałem klasy jQuery do walidacji we właściwym miejscu. field-validation-error i input-validation-error

    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
źródło
To podejście wygląda najlepiej dla mnie :). To też myślałem
Freshblood
3

Tak to zrobiłem z Bootstrap 2.xi 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
źródło
3

Proszę spojrzeć na następujące:
- https://gist.github.com/3030983
Myślę, że to najprostsze ze wszystkich.

EDYTOWAĆ

Kod z linku:

$('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
źródło
Wielkie dzięki za ostrzeżenie! Zobacz moją wersję dla Bootstrap, ale z etykietkami narzędzi. Moim zdaniem jest bardziej elegancki niż popovery.
Adrian P.
3

Wielkie dzięki za ostrzeżenie! Oto moja wersja dla Bootstrap, ale z etykietkami narzędzi. Moim zdaniem jest bardziej elegancki niż popovery. Wiem, że pytanie dotyczyło popoverów, więc nie głosuj z tego powodu. Może komuś się to spodoba. Uwielbiam, gdy czegoś szukam i znalazłem nowe pomysły w Stackoverflow. Uwaga: nie jest wymagana żadna adnotacja na formularzu.

    $('#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.
źródło
1
Próbowałem użyć twojego podejścia, ale zacząłem otrzymywać i błąd. Problem polega na tym, że jeśli używasz interfejsu JQuery, wystąpi konflikt, ponieważ oba używają podpowiedzi. Wiem, że jest na to rozwiązanie, ale chcę tylko, aby inni użytkownicy wiedzieli o tym.
Richard Pérez
+1 dla interfejsu użytkownika jQuery! Musisz skonfigurować niestandardowe pobieranie (jQueryUI lub Bootstrap), aby NIE zawierało funkcji Tooltip JS. Jeśli tego nie zrobisz, i tak będzie to konflikt dla każdej podpowiedzi.
Adrian P.
hej, próbowałem użyć twojego kodu z wyrażeniem regularnym i pojawił się błąd na stackoverflow.com/questions/16087351/… . Czy myślisz, że możesz pomóc? :)
psharma
@psharma Nie ma nic wspólnego z bootstrapem lub etykietką. Twój błąd jest deklaracją reguły, ponieważ otrzymałeś odpowiedź na swoje pytanie. komunikat o błędzie brzmiał: terminy są niezdefiniowane!
Adrian P.
Z jakiegoś powodu jest to jedyne rozwiązanie, które u mnie zadziałało. Dzięki!
suchanoob
2

Tak to się stało. Ale wymaga to wprowadzenia 2 zmian w skrypcie walidacji (dostałem tutaj kod bootstrap 1.4, a następnie zmodyfikowałem go - http://mihirchitnis.net/2012/01/customizing-error-messages-using-jquery-validate-plugin- dla-twitter-bootstrap / )

Moje wezwanie do zatwierdzenia:

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

Następnie musisz zmienić 2 rzeczy w jquery.validate.js
1. zastosuj tę poprawkę - https://github.com/bsrykt/jquery-validation/commit/6c3f53ee00d8862bd4ee89bb627de5a53a7ed20a
2. Po linii 647 (w funkcji showLabel utwórz część etykiety ) po linii .addClass(this.settings.errorClass)dodawania linii: .addClass("help-inline")
Ktoś może znaleźć sposób na zastosowanie drugiej poprawki w funkcji walidacji, ale nie znalazłem sposobu, ponieważ showLabel jest wywoływane po podświetleniu.

Andrej Bergant
źródło
2

To właśnie umieściłem w moim walidacji, aby zachować zgodność z wytycznymi Twitter Bootstrap. Komunikat walidacji błędu jest umieszczony w a <span class=help-inline>i chcemy podświetlić zewnętrzny kontener jako errorlub 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
źródło
2

Oto aktualizacja doskonałej odpowiedzi Kenny'ego Meyera powyżej . Wystąpiło kilka problemów, które uniemożliwiły mi pracę, które omówiłem w tym fragmencie:

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
źródło
Dziękuję za inicjatywę. Jak widzę, kod bardzo się zmienił :-)
Kenny Meyer
1

Nie jestem pewien, czy jest to istotne dla dyskusji, ponieważ oryginalny plakat prosił o haczyki do pokazywania / ukrywania wyskakujących okienek bootstrap.

Szukałem prostej walidacji, a popovers nie miało znaczenia. Related Post i pierwsza w wynikach wyszukiwania Google zostało już zaznaczone duplikat to pytanie. Warto więc wspomnieć o tym znakomitym jqValidation JS @ ReactiveRaven, trafnie nazwanym jqBootstrapValidation, który dobrze łączy się z Twitter Bootstrap. Konfiguracja zajmuje tylko kilka minut. Pobierz tutaj .

Mam nadzieję, że to dodaje wartości.

uchamp
źródło
1

tl; dr unikaj konieczności wyliczania jawnych popoverów za pomocą mapy skrótów do przechowywania identyfikatorów elementów i tworzenia popoverów w locie (mashup Jeffrey Gilbert i Kenny Meyer).

Oto moje podejście, które rozwiązuje problem migotania wspomniany przez innych, ale w przeciwieństwie do odpowiedzi @Jeffrey Gilbert nie używa listy ( errorStates), ale raczej używa mapy błędów . Mapy skrótów FTW. Chyba pamiętam, że czytałem gdzieś, że każdy problem w CS można rozwiązać za pomocą mapy mieszania :)

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

Podziękowania dla wszystkich innych, którzy przesłali pomysły na ten temat.

g33kz0r
źródło
0

Jeśli używasz powyższego kodu Kenny Meyer dla wyskakujących okienek, pamiętaj, że reguły sprawdzające zawartość pola, ale nie jest to wymagane, na przykład prawidłowy adres URL spowoduje, że wyskakujące okienko nie zniknie po wyczyszczeniu pola. Zobacz rozwiązanie onkeyup poniżej. Jeśli ktoś ma lepsze rozwiązanie, napisz.

onkeyup: function(element, event) {
            if($(element).valid())  {
                return $(element).popover("hide");
            }
        }
monsun
źródło