jQuery form validation

smallwall

Lt. Junior Grade
Registriert
Feb. 2014
Beiträge
446
Hi,
ich habe mir hier ein Snippet geladen, das Formvalidation macht.

http://devphp.de/formvalidation/no-reset.php

Es hatte ursprünglich keinen Reset, also habe ich ihn dazu geschrieben. Jetzt ist es nur so, dass beim betätigen die Felder auf validated stehen bleiben und nicht zurückgesetzt werden.
Wie kann ich das am besten ändern? So, dass der ursprüngliche Zustand gesetzt wird, nicht, dass einfach alles auf unvalid steht.

Hier ein Quote

Code:
<script type="text/javascript">
            $(document).ready(function () {
                $('.input-group input[required]').on('keyup change', function () {
                    var $form = $(this).closest('form'),
                            $group = $(this).closest('.input-group'),
                            $addon = $group.find('.input-group-addon'),
                            $icon = $addon.find('span'),
                            state = false;

                    if (!$group.data('validate')) {
                        state = $(this).val() ? true : false;
                    } else if ($group.data('validate') == "email") {
                        state = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/.test($(this).val())
                    } else if ($group.data('validate') == "length") {
                        state = $(this).val().length >= $group.data('length') ? true : false;
                    }

                    if (state) {
                        $addon.removeClass('danger');
                        $addon.addClass('success');
                        $icon.attr('class', 'glyphicon glyphicon-ok');
                    } else {
                        $addon.removeClass('success');
                        $addon.addClass('danger');
                        $icon.attr('class', 'glyphicon glyphicon-remove');
                    }

                    if ($form.find('.input-group-addon.danger').length == 0) {
                        $form.find('[type="submit"]').prop('disabled', false);
                    } else {
                        $form.find('[type="submit"]').prop('disabled', true);
                    }
                });

                $('.input-group input[required]').trigger('change');
                $('#reset').click(function(){
                    // what here?
                });

            });
        </script>
 
Javascript:
$('#reset').click(function(event) {
    event.preventDefault();
    $('.input-group input[required]').val('').trigger('change');
});
 
Zuletzt bearbeitet:
Wie immer, schnell und zuverlässig :) Vielen Dank.
Ergänzung ()

Code:
e.preventDefault = true;
Was ist das genau? Es funktioniert auch ohne. Und Netbeans meint auch "Global variable e is not declared". Es läuft zwar ohne Fehlermeldungen, aber ich würde es jetzt erstmal auskommentiern...
Edit: jetzt gibt er mir doch eine Fehlermeldung "Uncaught ReferenceError: e is not defined"... What?
 
Zuletzt bearbeitet:
"e" (oder "event") ist enthaelt das Click Event-Objekt. Durch event.preventDefault(); wird die Standard Funktionalitaet des Buttons vom Typ "reset" nicht ausgefuehrt, da wir hier eine eigene Funktion dafuer verwenden.
Achja den Code habe ich noch mal angepasst. preventDefault() ist bei jQuery eine Funktion und keine Variable :D
 
Es produziert aber auch eine Fehlermeldung. Ohne die Zeile läuft es tadellos. Warum sollte die Standardfunktion denn unterdrückt werden? Ich möchte doch, dass die Felder geleert werden, und zusätzlich soll noch etwas geschehen.
 
Da scheint NetBeans aber zu spinnen. Die Variable ist nicht global sondern ein Parameter. Oo Steht auch so in der Doku: https://api.jquery.com/event.preventDefault/

Die Felder werden ja durch deinen Code (.val('')) geleert anstatt vom Browser.
Sonst wuerden sie quasi zweimal geleert.
 
ReferenceError: event is not defined
sagt Firefox, Chrome stört es nicht. Das ist wieder mal eine Logik....
 
Schau mal ob der Parametername gleich ist. Ich hab beides geaendert (Siehe Code oben)
 
Ahja, function(event). Das war die Fehlermeldung. Habe nur die Zeile mit preventDefault kopiert.

Jetzt fehlt noch eine Funktion, die 2 Passwortfelder auf gleichen Inhalt validiert. Mal sehen, ob ich das allein schaffe...
Ergänzung ()

Bin jetzt bei folgenden Code angekommen.

Code:
<!DOCTYPE html>
<html lang="de">
    <head>
        <meta charset="utf-8">
        <title>Anmelden</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css" rel="stylesheet">
        <style type="text/css">
            .input-group-addon.success {
                color: rgb(255, 255, 255);
                background-color: rgb(92, 184, 92);
                border-color: rgb(76, 174, 76);
            }
            .input-group-addon.danger {
                color: rgb(255, 255, 255);
                background-color: rgb(217, 83, 79);
                border-color: rgb(212, 63, 58);
            }

            .pad { 
                display:block;
                width:30%;
                margin:40px auto; 
                padding: 50px 0;
                background-color: #eee;
            }
            .warning {
                background-color: #ff4;
            }

            body { 
                background: url('https://i.ytimg.com/vi/qp7ml8_0GjE/maxresdefault.jpg' ) no-repeat center center fixed;
                -webkit-background-size: cover;
                -moz-background-size: cover;
                -o-background-size: cover;
                background-size: cover;
            }
            label { font-weight: normal;}
        </style>
        <script src="//code.jquery.com/jquery-latest.min.js"></script>
        <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js"></script>
    </head>
    <body>
        <div class="container-fluid">
            <div class="pad">
                <div class="row">
                    <div class="col-sm-offset-2 col-sm-8 lead">Anmelden</div>
                </div>
                <div class="row">

                    <div class="col-sm-offset-2 col-sm-8">
                        <form method="post" action="">
                            <div class="form-group">
                                <label for="name">Name</label>
                                <div class="input-group" data-validate="length" data-length="3">
                                    <input type="text" class="form-control" name="name" id="name" value="" placeholder="" required autofocus="">
                                    <span class="input-group-addon danger"><span class="glyphicon glyphicon-remove"></span></span>
                                </div>
                            </div>
                            <div class="form-group">
                                <label for="email">E-Mail</label>
                                <div class="input-group" data-validate="email" data-length="6">
                                    <input type="text" class="form-control" name="email" id="email" value="" placeholder="" required>
                                    <span class="input-group-addon danger"><span class="glyphicon glyphicon-remove"></span></span>
                                </div>
                            </div>
                            <div class="form-group">
                                <label for="password" class="control-label">Passwort</label>
                                <div class="input-group" data-validate="password" data-length="6">
                                    <input type="password" class="form-control" id="password" name="password" placeholder="" maxlength="18" required="">
                                    <span class="input-group-addon danger"><span class="glyphicon glyphicon-remove"></span></span>
                                </div>
                            </div>
                            <div class="form-group">
                                <label for="pass" class="control-label">Passwort (wiederholen)</label>
                                <div class="input-group" data-validate="samepass" data-length="6">
                                    <input type="password" class="form-control" id="pass" name="pass" placeholder="" maxlength="18" required="">
                                    <span class="input-group-addon danger"><span class="glyphicon glyphicon-remove"></span></span>
                                </div>
                            </div>
                            <button type="submit" class="btn btn-primary col-xs-12" disabled>Anmelden</button>
                            <button type="reset"  class="btn btn-primary col-xs-12" id="reset">Formular leeren</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>

        <script type="text/javascript">
            $(document).ready(function () {
                $('.input-group input[required]').on('keyup change', function (what) {

                    var $form = $(this).closest('form'),
                            $group = $(this).closest('.input-group'),
                            $addon = $group.find('.input-group-addon'),
                            $icon = $addon.find('span'),
                            state = false,
                            warning = false;

                    if (!$group.data('validate')) {
                        state = $(this).val() ? true : false;
                    } else if ($group.data('validate') === "email") {
                        state = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/.test($(this).val());
                    } else if ($group.data('validate') === "length") {
                        state = $(this).val().length >= $group.data('length') ? true : false;
                    } else if ($group.data('validate') === "password") {
                        warning = $(this).val().length >= $group.data('length') ? true : false;
                        state = $(this).val().length >= $group.data('length') ? true : false;

                    } else if ($group.data('validate') === "samepass") {
                        var password = $('input[name=password]').val();
                        var samepass = $('input[name=pass]').val();
                        if ((password.length >= 6) && (samepass.length >= 6) && (password === samepass)) {
                            state = $(this).val() ? true : false;
                            console.log("Called too often...");
                        }
                    }

                    if (warning) {
                        $addon.removeClass('danger');
                        $addon.addClass('warning');
                        $icon.attr('class', 'glyphicon glyphicon-warning-sign');
                    } else {
                        if (state) {
                            $addon.removeClass('danger', 'warning');
                            $addon.addClass('success');
                            $icon.attr('class', 'glyphicon glyphicon-ok');
                        } else {
                            $addon.removeClass('success');
                            $addon.addClass('danger');
                            $icon.attr('class', 'glyphicon glyphicon-remove');
                        }
                    }

                    if ($form.find('.input-group-addon.danger').length === 0) {
                        $form.find('[type="submit"]').prop('disabled', false);
                    } else {
                        $form.find('[type="submit"]').prop('disabled', true);
                    }
                });
                $('.input-group input[required]').trigger('change');
                $('#reset').click(function (event) {
                    event.preventDefault();
                    $('.input-group input[required]').val('').trigger('change');
                });
            });
        </script>
    </body>
</html>

Jetzt habe ich nur das Problem, dass ich nicht weiß, wie ich an das Icon des jeweils anderen Passwortfelds komme. Ausserdem wird ein Zweig zu oft angesprungen (console.log...) Dort wird der Zweig manchmal 2x ausgeführt, später 1x beim change und 1x beim blur. Das ist nicht dramatisch, nur möchte ich das nicht :) Die Bootstrap class .warning scheint mir auch verbuggt zu sein, jedenfalls musste ich sie mir selbst dazu schreiben. Die Klasse .alert-warning ist zwar ähnlich, aber die Farbe gefällt mir nicht.
 
Zuletzt bearbeitet:
Habe es mal mit dem Bootstrap Validator von 1000hz umgesetzt. http://1000hz.github.io/bootstrap-validator/
Warum das Rad neuerfinden? :D

Deine Funktion wird bei jedem Tastendruck (keyup) und beim verlassen durch "change" ausgefuehrt.

HTML:
<!DOCTYPE html>
<html lang="de">
    <head>
        <meta charset="utf-8">
        <title>Anmelden</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css" rel="stylesheet">
        <style type="text/css">
            .pad {
                display:block;
                width:30%;
                margin:40px auto;
                padding: 50px 0;
                background-color: #eee;
            }

            body {
                background: url('https://i.ytimg.com/vi/qp7ml8_0GjE/maxresdefault.jpg' ) no-repeat center center fixed;
                -webkit-background-size: cover;
                -moz-background-size: cover;
                -o-background-size: cover;
                background-size: cover;
            }
            label { font-weight: normal;}
        </style>
    </head>
    <body>
        <div class="container-fluid">
            <div class="pad">
                <div class="row">
                    <div class="col-sm-offset-2 col-sm-8 lead">Anmelden</div>
                </div>
                <div class="row">

                    <div class="col-sm-offset-2 col-sm-8">
                        <form method="post" action="" data-toggle="validator">
                            <div class="form-group">
                                <label for="name">Name</label>
                                <div class="input-group">
                                    <input type="text" class="form-control" name="name" id="name" data-minlength="3" required autofocus="">
                                    <span class="input-group-addon"><span class="glyphicon form-control-feedback glyphicon-remove"></span></span>
                                </div>
                            </div>
                            <div class="form-group">
                                <label for="email">E-Mail</label>
                                <div class="input-group">
                                    <input type="email" class="form-control" name="email" id="email" pattern="^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$" required>
                                    <span class="input-group-addon"><span class="glyphicon form-control-feedback glyphicon-remove"></span></span>
                                </div>
                            </div>
                            <div class="form-group">
                                <label for="password" class="control-label">Passwort</label>
                                <div class="input-group" >
                                    <input type="password" class="form-control" id="password" name="password" data-minlength="6" required>
                                    <span class="input-group-addon"><span class="glyphicon form-control-feedback glyphicon-remove"></span></span>
                                </div>
                            </div>
                            <div class="form-group">
                                <label for="pass" class="control-label">Passwort (wiederholen)</label>
                                <div class="input-group">
                                    <input type="password" class="form-control" id="pass" name="pass" data-match="#password" required>
                                    <span class="input-group-addon"><span class="glyphicon form-control-feedback glyphicon-remove"></span></span>
                                </div>
                            </div>
                            <button type="submit" class="btn btn-primary col-xs-12">Anmelden</button>
                            <button type="reset"  class="btn btn-primary col-xs-12">Formular leeren</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>

        <script src="//code.jquery.com/jquery-latest.min.js"></script>
        <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/1000hz-bootstrap-validator/0.9.0/validator.js"></script>
        <script>
            $('button[type=reset]').on('click', function (event) {
                event.preventDefault();
                var $form = $(this).parent('form');
                $form.find('.glyphicon-ok').removeClass('glyphicon-ok').addClass('glyphicon-remove');
                $form.find('.form-group').removeClass('has-error has-success');
                $form.find('input').val('');
            });
        </script>
    </body>
</html>
 
Zuletzt bearbeitet: (Fix fuer: beim "Formular leeren" werden die alten Stati weiter angezeigt)
Warum das Rad neuerfinden
Naja, das ich nicht schlecht, aber....
-durch den autofocus wird das Feld "Name" direkt rot, wenn man nichts eingibt und z.b. auf das Passwort Feld wechselt.
-das Passwort Feld sollte nicht direkt grün werden, sondern erst gelb, und bei zwei gleichen Passwörten erst grün.
-wenn das Feld "pass" geändert wird, und nicht mehr matched, sollte "password" wieder gelb werden.
-wenn man in das Feld "Name" einen Buchstaben eingibt, wird es direkt rot, es sollte erst beim verlassen des Feldes rot werden.
-beim "Formular leeren" werden die alten Stati weiter angezeigt

Es ist zwar ok, und ich denke ich werde das so benutzen, aber es ist nicht das, was ich gerne hätte. Und die Skills es "neu zu erfinden" fehlen immer noch :)
 
Zuletzt bearbeitet:
Fix fuer: beim "Formular leeren" werden die alten Stati weiter angezeigt

Code:
<script>
    $('button[type=reset]').on('click', function (event) {
        event.preventDefault();
        var $form = $(this).parent('form');
        $form.find('.glyphicon-ok').removeClass('glyphicon-ok').addClass('glyphicon-remove');
        $form.find('.form-group').removeClass('has-error has-success');
        $form.find('input').val('');
    });
</script>


HTML:
<!DOCTYPE html>
<html lang="de">
    <head>
        <meta charset="utf-8">
        <title>Anmelden</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css" rel="stylesheet">
        <style type="text/css">
            .input-group-addon.success {
                color: rgb(255, 255, 255);
                background-color: rgb(92, 184, 92);
                border-color: rgb(76, 174, 76);
            }
            .input-group-addon.danger {
                color: rgb(255, 255, 255);
                background-color: rgb(217, 83, 79);
                border-color: rgb(212, 63, 58);
            }
            .input-group-addon.warning {
                background-color: #ff4;
                border-color: #ff4;
            }

            .pad {
                display:block;
                width:30%;
                margin:40px auto;
                padding: 50px 0;
                background-color: #eee;
            }

            body {
                background: url('https://i.ytimg.com/vi/qp7ml8_0GjE/maxresdefault.jpg' ) no-repeat center center fixed;
                -webkit-background-size: cover;
                -moz-background-size: cover;
                -o-background-size: cover;
                background-size: cover;
            }
            label { font-weight: normal;}
        </style>
        <script src="//code.jquery.com/jquery-latest.min.js"></script>
        <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js"></script>
    </head>
    <body>
        <div class="container-fluid">
            <div class="pad">
                <div class="row">
                    <div class="col-sm-offset-2 col-sm-8 lead">Anmelden</div>
                </div>
                <div class="row">

                    <div class="col-sm-offset-2 col-sm-8">
                        <form method="post" action="">
                            <div class="form-group">
                                <label for="name">Name</label>
                                <div class="input-group">
                                    <input type="text" class="form-control" name="name" id="name" data-minlength="3" required autofocus>
                                    <span class="input-group-addon invalid"><span class="glyphicon glyphicon-remove"></span></span>
                                </div>
                            </div>
                            <div class="form-group">
                                <label for="email">E-Mail</label>
                                <div class="input-group">
                                    <input type="email" class="form-control" name="email" id="email" required>
                                    <span class="input-group-addon invalid"><span class="glyphicon glyphicon-remove"></span></span>
                                </div>
                            </div>
                            <div class="form-group">
                                <label for="password" class="control-label">Passwort</label>
                                <div class="input-group">
                                    <input type="password" class="form-control" id="password" name="password" data-minlength="6" required>
                                    <span class="input-group-addon invalid"><span class="glyphicon glyphicon-remove"></span></span>
                                </div>
                            </div>
                            <div class="form-group">
                                <label for="passwordConfirm" class="control-label">Passwort (wiederholen)</label>
                                <div class="input-group" data-length="6">
                                    <input type="password" class="form-control" id="passwordConfirm" name="passwordConfirm" data-match="#password" required>
                                    <span class="input-group-addon invalid"><span class="glyphicon glyphicon-remove"></span></span>
                                </div>
                            </div>
                            <button type="submit" class="btn btn-primary col-xs-12" disabled>Anmelden</button>
                            <button type="reset"  class="btn btn-primary col-xs-12" id="reset">Formular leeren</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>

        <script type="text/javascript">
            $(document).ready(function ()
            {
                var updateInputStatus = function($input, isValid, showWarning)
                {
                    var $form = $input.closest('form'),
                        $group = $input.closest('.input-group'),
                        $addon = $group.find('.input-group-addon'),
                        $icon = $addon.find('.glyphicon');

                    if(typeof isValid === 'undefinded') isValid = false;
                    if(typeof showWarning === 'undefinded') showWarning = false;

                    // reset states
                    $addon.removeClass('danger warning success').addClass('invalid');
                    $icon.removeClass('glyphicon-ok glyphicon-warning-sign glyphicon-remove');

                    if(showWarning)
                    {
                        $addon.addClass('warning');
                        $icon.addClass('glyphicon-warning-sign');
                    }
                    else
                    {
                        $addon.addClass(isValid ? 'success' : 'danger');
                        $icon.addClass(isValid ? 'glyphicon-ok' : 'glyphicon-remove');

                        if(isValid) $addon.removeClass('invalid');
                    }
                    $form.trigger('validate');
                }

                $('input[type=text][required]').on('keyup change', function(e)
                {
                    var $this = $(this),
                        isValid = $this.val().trim().length > 0;

                    updateInputStatus($this, isValid);
                });

                $('input[type=text][data-minlength]').on('change', function(e)
                {
                    var $this = $(this),
                        isValid = $this.val().trim().length >= $this.data('minlength');

                    updateInputStatus($this, isValid);
                });

                $('input[type=email]').on('keyup change', function(e)
                {
                    var $this = $(this),
                        isValid = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/.test($this.val().trim());

                    updateInputStatus($this, isValid);
                });

                $('input[type=password]').on('keyup change', function(e)
                {
                    var $this = $(this)
                        isPasswordValid = false,
                        isConfirmValid = false,
                        warning = false;

                    if(typeof $this.data('match') === 'undefined')
                    {
                        // normal password field
                        $('input[data-match]').trigger('change');
                    }
                    else
                    {
                        // confirm password field
                        var $password = $($this.data('match'));

                        if(typeof $password.data('minlength') !== 'undefinded') {
                            isPasswordValid = $password.val().trim().length >= $password.data('minlength');
                        } else {
                            isPasswordValid = $password.val().trim().length > 0;
                        }

                        isConfirmValid = $password.val().trim() === $this.val().trim();

                        updateInputStatus($password, isPasswordValid, !isConfirmValid && isPasswordValid);
                        updateInputStatus($this, isConfirmValid && isPasswordValid);
                    }
                });


                $('form').on('validate', function(e)
                {
                    var $this = $(this);

                    var submitIsEnabled = $this.find('.invalid').length !== 0;
                    $this.find('[type="submit"]').prop('disabled', submitIsEnabled);
                });

                $('button[type=reset]').click(function(e)
                {
                    e.preventDefault();
                    $('input[required]').val('');

                    var $this = $(this),
                        $form = $this.closest('form'),
                        $addon = $form.find('.input-group-addon'),
                        $icon = $addon.find('.glyphicon');

                    // reset states
                    $addon.removeClass('danger warning success').addClass('invalid');
                    $icon.removeClass('glyphicon-ok glyphicon-warning-sign').addClass('glyphicon-remove');
                    $form.find('[type="submit"]').prop('disabled', true);
                });
            });
        </script>
    </body>
</html>
 
Zuletzt bearbeitet: (Habe das Rad neu erfunden! Fix. Keyup.)
Sehr cool :) Die Passwortfelder sind optimal, nur Name und E-Mail werden erst grün, wenn man das Feld verlässt.
 
Stimmt bei denen muesstest du dann noch das Event "keyup" hinzufuegen.
 
Perfekt. Jetzt nur noch eine Frage: Wieso nimmt man dort nicht keydown? Wenn man keydown benutzt wird die min-length auch um 1 erhöht. Statt 3 Zeichen braucht man dann 4 für "Name". Keydown empfinde ich aber als direkter und sinniger...
 
Naja keydown hat das Problem mit der "erhöhten Länge". Z.b. steht in dem Pattern für die Email ....{2,4} für die Länge der Top Level Domain. Mit keydown wird daraus 3,5 oder 3,4, d.h. eine .de E-Mail kann man gar nicht eingeben. Das müsste man dann ändern. Da nehme ich doch keyup und die Länge stimmt....
Ergänzung ()

Eine Sache noch: Wie kann man das gelbe Warndreieck für das Passwort erst anzeigen wenn die min-length erreicht wurde?
 
Zeile 171 aendern (Siehe oben):
Code:
updateInputStatus($password, isPasswordValid, !isConfirmValid && isPasswordValid);
 
Zuletzt bearbeitet: (Warndreieck)
keyup/down finde ich etwas merkwürdig. Die werden auch bei z.B. Pfeiltasten gefeuert, was bei Formularen selten Sinn macht.
Wenn man etwas bei jeder Input Änderung ausführen will, würde ich einfach das "input" Event verwenden. Sachen wie copy / paste, drag /drop gehen dann auch Problemlos, denn "input" wird bei wirklich jeder richtigen Änderung gefeuert.
 
Oha, vielen Dank für den Hinweis. Input scheint ähnlich wie keyup zu funktionieren. In meinem Chrome wird es aber z.b. nicht getriggert, wenn man mit rechter Maustaste->Einfügen das Feld befüllt (in meinem Firefox auch nicht). CTRL+V ist ja wie keyup/down, also auch kein wirklicher Vorteil. Aber gut zu wissen, dass es den Event gibt.
 
Zurück
Oben