webentwicklung-frage-antwort-db.com.de

Konflikt zwischen jQuery Validate und maskierter Eingabe

Ich habe ein Formular, das jQuery Validate und Masked Input für die Felder für Telefonnummer und US-Postleitzahl verwendet.

Bei einer US-amerikanischen Postleitzahl können Sie zum Beispiel nur Zahlen eingeben und erzwingen entweder das Format "99999" oder "99999-9999" (wobei 9 eine beliebige Zahl sein kann). Die Validate-Regel erfordert dasselbe. In einigen Fällen markiert Validate jedoch ein Feld als ungültig, wenn es tatsächlich gültig sein sollte.

Code-Besonderheiten

Die von jQuery Validate für das Feld "Postleitzahl" verwendete Regex lautet ^\d{5}$|^\d{5}\-\d{4}$.

Die Maske, die ich mit maskierter Eingabe anwende, ist .mask('99999?-9999')

Schritte zum Reproduzieren

Ein Konflikt zwischen ihnen entsteht, wenn ich Folgendes mache:

  • Füllen Sie eine ungültige Postleitzahl aus (z. B. drei Ziffern)
  • Tab vom Feld weg. Maskierte Eingabe löscht die Eingabe (erwartetes Verhalten) und jQuery Validate markiert sie als ungültig, da sie leer ist (auch erwartet).
  • Gehen Sie zurück zum Feld "Zip" und geben Sie eine gültige 5-stellige Zip ein.
  • Tab vom Feld weg. Es wird immer noch als ungültig markiert. Das ist unerwartet .

Dieses Problem tritt nicht auf, wenn ich eine 9-stellige Postleitzahl ausfülle. 

Hypothese

Ich denke, dieser Fehler liegt darin, dass Masked Input im Falle des 5-stelligen Zip-Codes vorübergehend "-____" eingefügt hat, um dem Benutzer anzuzeigen, dass er optional einen Bindestrich und vier weitere Ziffern eingeben kann. Dies wird bei Unschärfe entfernt, aber bevor es 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 das Feld "Zip" durchläuft, wenn das Formular anschließend erneut überprüft wird. Ich habe dies auf zwei Arten gemacht:

  • Mit dem Absenden des Formulars; Alle Felder werden erneut überprüft, wenn Sie auf die Schaltfläche "Senden" klicken, das Feld "ZIP" durchläuft und das Formular übermittelt.
  • Durch Einrichten eines blur-Ereignisses, das dieses bestimmte Feld erneut überprüft. Zum Beispiel:

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

Dies kann als hackige Lösung dienen , ist jedoch nicht sehr zufriedenstellend, da 1) die Standardeinstellungen bei Unschärfe bereits neu validiert werden, sodass dies wiederholt wird und 2) neben dem normalen Validate zusätzlicher Code erforderlich ist Regeln.

Ist noch jemand in dieses Problem geraten? Haben Sie eine elegantere Lösung als einen zusätzlichen Listener für Unschärfeereignisse einrichten?

Update: Anwendung der Hacky-Lösung

Selbst die Anwendung der hacky-Lösung oben funktioniert nicht so gut wie ich möchte. Das funktioniert zum Beispiel nicht:

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

... und das auch nicht:

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

... aber das tut:

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

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

25
Nathan Long

Ich suchte tatsächlich nach einer Antwort auf diese genaue Frage. Endlich herausgefunden, eine zuverlässigere Lösung zu finden. 

Da ich meine eigene Validierungsmethode für die Postleitzahl definiere, habe ich sie so geändert, dass der Bindestrich entfernt werden würde, wenn die Postleitzahl nach dem Entfernen des Platzhalters aus dem Wert 6 war.

Es sah so 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 die vom Eingabe-Plugin hinzugefügten Platzhalter und der Bindestrich entfernt, wenn die eingegebene Postleitzahl nur 5 numerische Ziffern enthält (6 einschließlich des Bindestrichs). So wird es richtig validiert.

9
Adrian

Ich habe folgende Lösung ausprobiert, und es funktioniert wie ein Zauber.

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

Das Problem wird durch die Ereignisreihenfolge ausgelöst. Wenn ein Element maskiert ist, wird es durch maskedinput plugin für blur validiert, dasselbe Element wird jedoch durch validator plugin für focusout validiert Browser), die vor der Unschärfe von maskedinput aufgerufen wird.

In dieser Situation hat das Eingabeelement den Wert "(___) ___ __ __", wenn der Validator nach dem Wert sucht. Wenn der Code das Unschärfeereignis von maskedinput erreicht, prüft und löscht das Plugin den Wert, da es keine gültige Eingabe ist.

Das Validierungsergebnis kann für jeden Validierungsfall unterschiedlich sein. Zum Beispiel required-Regeln werden mit Erfolg übergeben, da das Element einen Wert hat. Nicht erforderliche number-Felder schlagen fehl, selbst wenn wir die Eingabe leer lassen, da eine Maske wie "999" als 12_ getestet werden kann.

der obige Code prüft, ob eine Form der maskierten Eingabe mit einer Validierung verknüpft ist, und ruft den Fokus-Ereignishandler zurück. Da unser Handler der neueste ist, wird er hoffentlich endlich angerufen.

Eine Warnung, Code kopiert einfach das Verhalten des Validierungs-Plugins. Es wird wahrscheinlich für ein Jahrzehnt funktionieren, kann aber fehlschlagen, wenn das Validierungs-Plugin entscheidet, etwas anderes als jetzt zu tun.

mit freundlichen Grüßen

11
edokan

Hängen Sie einfach die Funktion mask () an und fügen Sie eine zusätzliche Logik hinzu, um Ihre eigene Unschärfelogik nach der Unschärfelogik der Standardmaske 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));
    });
}

Möglicherweise stellen Sie auch die Funktion 'exists ()' fest. Dies ist etwas, was ich häufig mit meinen jQuery-Selektoren benutze:

//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;
}
7
Greg H

Ich hatte ein ähnliches Problem und konnte dieses Problem lösen, indem das standardmäßige Platzhalterzeichen in eine leere Zeichenfolge geändert wurde.

Ich verwendete eine .mask('9?99'); und überprüfte mit einer einfachen 'Zahlen'-Regel und hatte die gleiche Art von Konflikt.

Ich habe die Maskendeklaration in .mask('9?99',{placeholder:''}); geändert und ... kein Konflikt mehr. :)

In Ihrem Fall liegt möglicherweise ein Problem vor, da der - in der Postleitzahl immer vom Masken-Plugin in das Formular eingefügt wird. Ich denke, Sie können den regulären Ausdruck in ^\d{5}\-$|^\d{5}\-\d{4}$ ändern (der in beiden Fällen mit dem Bindestrich übereinstimmt), und er sollte dann bestätigen.

Wie auch immer, du hast vor einer Weile gepostet und brauchst das wahrscheinlich nicht mehr, aber vielleicht hilft es jemand anderem. :)

5
Miguel Pinto

Ist es wichtig, dass Sie die Bindung ausführen? Gibt es zum Beispiel einen Unterschied zwischen

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

und

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

Ich denke, dass die Bindungen in Ordnung gehen sollten.

1
Jarrett Meyer

Ich habe einige der Lösungen ausprobiert, aber keine hat bei mir funktioniert. Ich verwende 'bootstrapValidator' ( http://bootstrapvalidator.com/ ) und 'jquery.maskedinput' ( http://digitalbush.com/ projects/masked-input-plugin/ ) Wenn also noch jemand dieses Problem hat, war meine Lösung:

Meine Eingabe wurde folgendermaßen gekennzeichnet:

<input type="text" class="form-control" id="telefone" placeholder="(__) ____-_____" name="telefone" required>

Und das vollständige Skript wie folgt:

$(document).ready(function() {
   var telefone = $('#telefone'), //THAT'S MY INPUT WITH MASK
       form = telefone.parents("form"), //THAT'S MY FORM WITH THE VALIDATE
       alteredField = false; //THAT'S A FLAG TO SSE IF THE INPUT WAS ALTERED

            // APPLY MY MASK
            telefone.mask('(99) 9999-9999?9');

            // FOCUS ON ANY INPUT
            form.find('input[type=text]').focus(function(){
                // REMOVE THE VALIDATION STATUS
                $(form).data('bootstrapValidator').updateStatus($(this).attr('name'), 'NOT_VALIDATED');
                // ENABLE THE SUBMIT BUTTON
                $(form).data('bootstrapValidator').disableSubmitButtons(false);
            });

            // FOCUS ON THE MASKED INPUT
            telefone.focus(function(){
                // DISABLE THE VALIDATE
                $(form).data('bootstrapValidator').enableFieldValidators('telefone', false);
                // ENABLE THE SUBMIT BUTTON
                $(form).data('bootstrapValidator').disableSubmitButtons(false);
            }).blur(function(){ // BLUR ON THE MASKED INPUT
                // GET THE INPUT VALUE
                var value = telefone.val();
                // ENABLE THE VALIDATE 
                $(form).data('bootstrapValidator').enableFieldValidators('telefone', true);
                // CHECK IF THE VALUE IS EMPTY
                if(value != ""){
                    // CHANGE THE STATUS OF THE INPUT TO VALID 
                    $(form).data('bootstrapValidator').updateStatus('telefone', 'VALID')
                    // ACTIVE THE FLAG
                    alteredField = true;
                }else if (alteredField) { // IF THE INPUT WAS ALTERED BEFORE AND DON'T HAVE VALUE
                    // CHANGE THE STATUS OF THE INPUT TO INVALID
                    $(form).data('bootstrapValidator').updateStatus('telefone', 'INVALID')
                };
            });

        });

Dieser Code ändert das Standardverhalten des 'bootstrapValidator', aber ich musste den Fehler nur so beheben. 

Ich kenne mich mit Leistungsproblemen nicht aus. Bitte ändern und verbessern Sie den Code ^^ Hoffen Sie, dass diese Hilfe ^ _ ^ hilft