25 Stimmen

Konflikt zwischen jQuery Validate und maskierter Eingabe

Ich habe ein Formular, das beides verwendet jQuery validieren y Maskierte Eingabe für die Felder Telefonnummer und US-Postleitzahl.

Für eine US-Postleitzahl zum Beispiel erlaubt die maskierte Eingabe nur die Eingabe von Zahlen und erzwingt entweder das Format "99999" oder "99999-9999" (wobei 9 eine beliebige Zahl sein kann). Die Validierungsregel verlangt dasselbe. In einigen Fällen wird jedoch ein Feld als ungültig markiert, obwohl es eigentlich gültig sein sollte.

Besonderheiten des Codes

Der Regex, den jQuery Validate für das Postleitzahlenfeld verwendet, lautet ^\d{5}$|^\d{5}\-\d{4}$ .

Die Maske, die ich mit Masked Input anwende, lautet .mask('99999?-9999')

Schritte zur Reproduktion

Zu einem Konflikt zwischen ihnen kommt es, wenn ich Folgendes tue:

  • Geben Sie eine ungültige Postleitzahl ein (z. B. drei Ziffern)
  • Tabulator weg vom Feld. Masked Input löscht die Eingabe (erwartetes Verhalten) und jQuery Validate markiert sie als ungültig, weil sie leer ist (ebenfalls erwartet).
  • Gehen Sie zurück zum Feld für die Postleitzahl und geben Sie eine gültige 5-stellig Reißverschluss.
  • Tab weg vom Feld. Sie ist immer noch als ungültig gekennzeichnet. Dies ist unerwartet .

Dieses Problem ist no passieren, wenn ich eine 9-stellige Postleitzahl eingebe.

Hypothese

Ich denke, dass dieser Fehler darauf zurückzuführen ist, dass im Falle der 5-stelligen Postleitzahl die maskierte Eingabe vorübergehend "-____" eingefügt hat, um dem Benutzer zu zeigen, dass er optional einen Bindestrich und vier weitere Ziffern eingeben kann. Dieser wird bei Unschärfe entfernt, aber bevor er entfernt wird, wird das Feld überprüft und schlägt fehl, da Unterstriche nicht zulässig sind.

Diese Hypothese wird durch die Tatsache gestützt, dass bei einer erneuten Validierung des Formulars das Feld für die Postleitzahl akzeptiert wird. Ich habe dies auf zwei Arten getan:

  • Beim Absenden des Formulars werden alle Felder erneut validiert, wenn auf die Schaltfläche "Absenden" geklickt wird, das Feld für die Postleitzahl akzeptiert wird und das Formular abgesendet wird.

  • Durch die Einrichtung einer blur Ereignis, das dieses spezifische Feld erneut validiert. Zum Beispiel:

    $("#zipcode").blur(function(){ $(this).closest('form').validate().element($(this)); });

Dies kann als Notlösung dienen , ist aber nicht sehr zufriedenstellend, weil 1) die Standardeinstellungen bereits eine erneute Validierung bei Unschärfe vorsehen, so dass dies eine Wiederholung ist, und 2) es zusätzlichen Code neben den normalen Validierungsregeln erfordert.

Ist noch jemandem dieses Problem aufgefallen? Haben Sie eine elegantere Lösung? als einen zusätzlichen Unschärfe-Ereignis-Listener einzurichten?

Update: Anwendung der hackigen Lösung

Selbst die Anwendung der obigen Notlösung funktioniert nicht so gut, wie ich es gerne hätte. Zum Beispiel funktioniert dies nicht:

$appDiv.delegate('input,select,textarea','blur',function(){
  $(this).closest('form').validate().element($(this));
});

...und das hier auch nicht:

$('input,select,textarea').live('blur',function(){
  $(this).closest('form').validate().element($(this));
});

...aber das hier schon:

$('input,select,textarea').each(function(){
  $(this).blur(function(){
    $(this).closest('form').validate().element($(this));
  });
});

Da diese Elemente per AJAX geladen werden, muss die .each Version muss jedes Mal ausgeführt werden, wenn ein Formularabschnitt geladen wird.

11voto

Erdogan Kurtur Punkte 3443

Ich habe folgende Lösung ausprobiert, und sie funktioniert wunderbar.

$("[data-input-type=phone]", "body")
  .mask("(999) 999 99 99")
  .bind("blur", function () {
    // force revalidate on blur.

    var frm = $(this).parents("form");
    // if form has a validator
    if ($.data( frm[0], 'validator' )) {
      var validator = $(this).parents("form").validate();
      validator.settings.onfocusout.apply(validator, [this]);
    }
  });

Der Auslöser des Problems ist die Reihenfolge der Ereignisse. Wenn ein Element maskiert ist, wird es durch das maskedinput-Plugin validiert bei blur aber dasselbe Element wird vom Validator-Plugin auf focusout Ereignis (das ein Wrapper für Blur auf Nicht-IE-Browsern ist), das vor dem Blur von maskedinput aufgerufen wird.

In diesem Fall hat das Eingabeelement den Wert "(___) ___ __ __" wenn der Validator den Wert prüft. Wenn der Code das Blur-Ereignis von maskedinput erreicht, prüft und löscht das Plugin den Wert, da es sich nicht um eine gültige Eingabe handelt.

Das Ergebnis der Validierung kann von Fall zu Fall unterschiedlich ausfallen. Zum Beispiel required Regeln sind erfolgreich, da das Element einen Wert hat. nicht erforderlich number Felder scheitern, selbst wenn wir die Eingabe leer lassen, da eine Maske wie "999" kann getestet werden als 12_

Der obige Code testet, ob das Formular der maskierten Eingabe eine Validierung enthält, und ruft den Focusout-Eventhandler auf. Da unser Handler als letzter angehängt ist, wird er hoffentlich endlich aufgerufen.

Eine Warnung, der Code kopiert einfach das Verhalten des Validierungs-Plugins. Es wird wahrscheinlich für ein Jahrzehnt arbeiten, aber kann fehlschlagen, wenn Validierung Plugin entscheidet, Dinge anders als jetzt zu tun.

mit freundlichen Grüßen

10voto

Adrian Punkte 2871

Ich war eigentlich auf der Suche nach einer Antwort auf genau diese Frage. Am Ende habe ich einen zuverlässigeren Ausweg gefunden.

Da ich meine eigene Validierungsmethode für die Postleitzahl definiere, habe ich sie so geändert, dass sie den Bindestrich entfernt, wenn die Länge der Postleitzahl 6 beträgt, nachdem ich den Platzhalter aus dem Wert entfernt habe.

Sie sah folgendermaßen aus:

$.validator.addMethod("zipcode", function(postalcode, element) {
            //removes placeholder from string
            postalcode = postalcode.split("_").join("");

            //Checks the length of the zipcode now that placeholder characters are removed.
            if (postalcode.length === 6) {
                //Removes hyphen
                postalcode = postalcode.replace("-", "");
            }
            //validates postalcode.
            return this.optional(element) || postalcode.match(/^\d{5}$|^\d{5}\-\d{4}$/);
        }, "Please specify a valid zip code");

Bei der von mir überprüften Postleitzahl werden also die vom Eingabe-Plugin hinzugefügten Platzhalter und der Bindestrich entfernt, wenn die eingegebene Postleitzahl nur 5 numerische Ziffern hat (6 einschließlich Bindestrich). So wird sie richtig validiert.

7voto

Greg H Punkte 71

Verbinden Sie sich einfach mit der Funktion mask() und fügen Sie eine zusätzliche Logik hinzu, um Ihre eigene Weichzeichnerlogik nach der standardmäßigen Weichzeichnerlogik der Maske auszulösen:

//Store the original mask function
var origMaskFn = $.fn.mask;

$.fn.mask = function (mask, settings) {

    //Call the original function applying the default settings
    origMaskFn.apply(this, [mask, settings]);

    //Manually validate our element on blur to prevent unobtrusive messages
    //from showing before the mask is properly scrubbed
    $(this).bind('blur', function () {
        var $form = $(this).parents('form');
        if (!$form.exists())
            return;

        var validator = $form.validate().element($(this));
    });
}

Vielleicht fällt Ihnen auch die Funktion 'exists()' auf. Dies ist etwas, das ich viel mit meinem jQuery Selektoren verwenden:

//Function to detect if a jQuery elements exists.  i.e.:
//      var $element = $(selector);
//      if($element.exists()) do something...

$.fn.exists = function () {
    return this.length !== 0;
}

6voto

Miguel Pinto Punkte 86

Ich hatte ein ähnliches Problem und konnte es lösen, indem ich das Standardplatzhalterzeichen in eine leere Zeichenfolge umwandelte.

Ich habe eine .mask('9?99'); und validierte mit einer einfachen "Zahl"-Regel und hatte den gleichen Konflikt.

Ich änderte die Maskendeklaration in .mask('9?99',{placeholder:''}); und... keine Konflikte mehr :)

In Ihrem Fall gibt es ein mögliches Problem, da die - in der Postleitzahl, die durch das Masken-Plugin immer in das Formular eingefügt wird. Ich denke, Sie können die Regexp ändern in ^\d{5}\-$|^\d{5}\-\d{4}$ (in beiden Fällen mit dem Bindestrich übereinstimmend) und es sollte dann gültig sein.

Wie auch immer, Sie haben schon vor einer Weile gepostet und brauchen das wahrscheinlich nicht mehr, aber vielleicht hilft es ja jemand anderem :)

1voto

Jarrett Meyer Punkte 18916

Spielt es eine Rolle, in welcher Reihenfolge Sie die Bindung vornehmen? Gibt es zum Beispiel einen Unterschied zwischen

$(function() {
  var $form = $("#myForm"), $zip = $("#zip");
  $zip.mask("99999?-9999");
  $form.validate();
});

y

$(function() {
  var $form = $("#myForm"), $zip = $("#zip");
  $form.validate();
  $zip.mask("99999?-9999");
});

Ich denke, dass die Bindungen in der Reihenfolge feuern sollten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X