Überprüfen Sie die Felder, nachdem der Benutzer ein Feld verlassen hat


92

Mit AngularJS kann ich verwenden ng-pristineoder ng-dirtyerkennen, ob der Benutzer das Feld eingegeben hat. Ich möchte die clientseitige Validierung jedoch erst durchführen, nachdem der Benutzer den Feldbereich verlassen hat. Dies liegt daran, dass ein Benutzer, der ein Feld wie E-Mail oder Telefon eingibt, immer einen Fehler erhält, bis er seine vollständige E-Mail eingegeben hat. Dies ist keine optimale Benutzererfahrung.

Beispiel


AKTUALISIEREN:

Angular wird jetzt mit einem benutzerdefinierten Unschärfeereignis ausgeliefert: https://docs.angularjs.org/api/ng/directive/ngBlur


3
Ich denke, dass dies etwas ist, das Angularjs hätte unterstützen sollen ...
CSG

Vielleicht. Die integrierte Formularvalidierung funktioniert recht gut, sodass ich nicht weiß, ob ich dies einbauen möchte. Schließlich möchte ich, dass Angular in den meisten Anwendungsfällen sofort validiert wird. dh in einem Zahlenfeld möchte ich, dass das Formular sofort ungültig wird, wenn der Benutzer mit der Eingabe von Buchstaben beginnt.
mcranston18

11
Validierung auf Unschärfe ist seit 15 Jahren üblich ...
Olivvv

Antworten:


75

Angular 1.3 verfügt jetzt über ng-model-Optionen, und Sie können die Option { 'updateOn': 'blur'}beispielsweise auf festlegen und sogar entprellen, wenn die Verwendung entweder zu schnell eingibt oder Sie einige teure DOM-Vorgänge (wie das Schreiben eines Modells) speichern möchten an mehrere DOM-Stellen und Sie möchten nicht, dass bei jedem Tastendruck ein $ Digest-Zyklus stattfindet.)

https://docs.angularjs.org/guide/forms#custom-triggers und https://docs.angularjs.org/guide/forms#non-immediate-debounce-model-updates

Standardmäßig löst jede Änderung des Inhalts eine Modellaktualisierung und Formularüberprüfung aus. Sie können dieses Verhalten mithilfe der Anweisung ngModelOptions überschreiben, um nur an die angegebene Liste von Ereignissen zu binden. Ie ng-model-options = "{updateOn: 'blur'}" wird erst aktualisiert und validiert, wenn das Steuerelement den Fokus verliert. Sie können mehrere Ereignisse mithilfe einer durch Leerzeichen getrennten Liste festlegen. Dh ng-model-options = "{updateOn: 'mousedown blur'}"

Und entprellen

Sie können die Aktualisierung / Validierung des Modells verzögern, indem Sie den Debounce-Schlüssel mit der Direktive ngModelOptions verwenden. Diese Verzögerung gilt auch für Parser, Validatoren und Modellflags wie $ schmutzig oder $ makellos.

Ie ng-model-options = "{debounce: 500}" wartet seit der letzten Inhaltsänderung eine halbe Sekunde, bevor die Modellaktualisierung und Formularüberprüfung ausgelöst wird.


2
In den meisten Fällen wird das Problem dadurch nicht behoben, da Sie wahrscheinlich noch ng-changeEreignisse empfangen möchten, bevor der Benutzer das Feld verlassen hat. In meinem Fall fordere ich beispielsweise neue Daten von meiner API an, sobald das Eingabefeld gültig ist, aber ich möchte keine Fehlermeldung anzeigen, sobald sie ungültig ist - ich möchte dies nur tun, wenn dies der Fall ist ungültig und das Unschärfeereignis ist aufgetreten.
Tom

@ Tom Ich teste 1.3.0 rc-3und es nicht Feuer , changebis blur, überprüfen Sie diese: plnkr.co/edit/RivVU3r7xfHO1hUybqMu?p=preview
Gill Bates

Dies sollte wirklich die akzeptierte, beste Antwort sein. Warum eine Direktive hinzufügen, wenn Sie eine einzelne Eigenschaft hinzufügen können?
Dan Hulton

92

Ab Version 1.3.0 ist dies problemlos möglich $touched, nachdem der Benutzer das Feld verlassen hat.

<p ng-show="form.field.$touched && form.field.$invalid">Error</p>

https://docs.angularjs.org/api/ng/type/ngModel.NgModelController


1
Würde das nicht immer noch die Validierung nach jeder Eingabe ausführen? OP gab an, dass er die Validierung erst durchführen möchte, nachdem der Benutzer das Feld verlassen hat.
Comecme

@comecme ja, die Standard-ng-Modell-Optionen sind, updateOn: 'default'was bedeutet, für Eingaben, Tasten und für
Auswahlen

5
Der große Fehler hierbei ist jedoch, dass Sie nicht die gleiche Validierungserfahrung haben, wenn Sie wieder vor Ort sind. Sie befinden sich wieder auf dem ersten Platz, wo es bei jedem Tastendruck überprüft wird, da es bereits auf Berühren eingestellt ist. Ich bin überrascht, dass dies so viele positive Stimmen bekommen hat.
Dudewad

3
@dudewad das ist richtig, aber ich denke, es ist das gewünschte Verhalten UX-weise - wenn Sie zu einem ungültigen Feld zurückkehren, sollte die Fehlermeldung bestehen bleiben, bis der Wert gültig ist, nicht bis Sie den ersten Buchstaben eingegeben haben.
Danbars

@dudewad Würde es dem Benutzer nicht helfen, bei jedem Druck zu validieren, nachdem er bereits wusste, dass ein Feld nach dem ersten Ausfüllen ungültig war? Sobald sie wissen, dass das Feld ungültig ist, möchten sie wahrscheinlich schnell wissen, wann das Feld gültig ist, und eine Überprüfung bei jedem Tastendruck würde diesen Prozess möglicherweise beschleunigen.
Alan Dunning

32

Ich habe dieses Problem gelöst, indem ich die Vorschläge von @jlmcdonald erweitert habe. Ich habe eine Direktive erstellt, die automatisch auf alle Eingabe- und Auswahlelemente angewendet wird:

var blurFocusDirective = function () {
    return {
        restrict: 'E',
        require: '?ngModel',
        link: function (scope, elm, attr, ctrl) {
            if (!ctrl) {
                return;
            }

            elm.on('focus', function () {
                elm.addClass('has-focus');

                scope.$apply(function () {
                    ctrl.hasFocus = true;
                });
            });

            elm.on('blur', function () {
                elm.removeClass('has-focus');
                elm.addClass('has-visited');

                scope.$apply(function () {
                    ctrl.hasFocus = false;
                    ctrl.hasVisited = true;
                });
            });

            elm.closest('form').on('submit', function () {
                elm.addClass('has-visited');

                scope.$apply(function () {
                    ctrl.hasFocus = false;
                    ctrl.hasVisited = true;
                });
            });

        }
    };
};

app.directive('input', blurFocusDirective);
app.directive('select', blurFocusDirective);

Dadurch werden verschiedene Elemente hinzugefügt has-focusund has-visitedklassifiziert, wenn der Benutzer die Elemente fokussiert / besucht. Sie können diese Klassen dann zu Ihren CSS-Regeln hinzufügen, um Validierungsfehler anzuzeigen:

input.has-visited.ng-invalid:not(.has-focus) {
    background-color: #ffeeee;   
}

Dies funktioniert gut, da Elemente immer noch $ ungültige Eigenschaften usw. erhalten, aber das CSS kann verwendet werden, um dem Benutzer eine bessere Erfahrung zu bieten.


2
Warum ist '? NgModel' anstelle von 'ngModel' erforderlich? Ich verstehe, dass ngModel dort sein muss, aber warum das Fragezeichen?
Noremac

2
Danke für die Idee. Sollte darauf hinweisen, dass es jQuery erfordert (ich denke - konnte kein .closest () in jql sehen).
Iandotkelly

1
Nicht alle <input> -Elemente werden von ngModel unterstützt (z. B. input type = submit). Das ? erfordert ngModel nur für Elemente, die es unterstützen.
Chmanie

5
Um ehrlich zu sein, sollten Sie nicht von der Winkelmethode zum Festlegen von Eingabefeldzuständen wie abweichen formName.inputName.$dirty. Ich würde vorschlagen, die Direktive zu bearbeiten, um einen ähnlichen Booleschen formName.inputName.$focusedWert wie zu schreiben , anstatt Klassennamen für Unschärfe und Boolesche Werte für die Validierung zu verwenden.
Tom

17

Ich habe das mit einem ziemlich einfachen Stück CSS geschafft. Dies erfordert, dass die Fehlermeldungen Geschwister der Eingabe sind, auf die sie sich beziehen, und dass sie eine Klasse von haben error.

:focus ~ .error {
    display:none;
}

Nachdem diese beiden Anforderungen erfüllt wurden, werden alle Fehlermeldungen in Bezug auf ein fokussiertes Eingabefeld ausgeblendet, was meiner Meinung nach eckig sein sollte. Scheint wie ein Versehen.


2
Ahh. Dies ist ein kluger Weg. Ich ziehe dies dem Schreiben von Javascript vor.
Deck

5
Der Nachteil dieses Ansatzes ist, dass wenn jemand einen Fehler korrigiert, der Fehler nicht mehr sichtbar ist, was nicht ideal ist. Ideal wäre, dass der Fehler erst bei Unschärfe angezeigt wird, aber erst verschwindet, wenn er korrigiert ist.
Chris Nicola

4

Dies scheint standardmäßig in neueren Versionen von Angular implementiert zu sein.

Die Klassen ng-unberührt und ng-berührt werden jeweils vor und nach dem Fokus des Benutzers auf ein validiertes Element festgelegt.

CSS

input.ng-touched.ng-invalid {
   border-color: red;
}

4

In Bezug auf die Lösung von @ lambinator ... Ich habe den folgenden Fehler in angle.js 1.2.4 erhalten:

Fehler: [$ rootScope: inprog] $ Digest wird bereits ausgeführt

Ich bin nicht sicher, ob ich etwas falsch gemacht habe oder ob dies eine Änderung in Angular ist, aber das Entfernen der scope.$applyAnweisungen hat das Problem behoben und die Klassen / Zustände werden immer noch aktualisiert.

Wenn dieser Fehler ebenfalls auftritt, versuchen Sie Folgendes:

var blurFocusDirective = function () {
  return {
    restrict: 'E',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) {
        return;
      }
      elm.on('focus', function () {
        elm.addClass('has-focus');
        ctrl.$hasFocus = true;
      });

      elm.on('blur', function () {
        elm.removeClass('has-focus');
        elm.addClass('has-visited');
        ctrl.$hasFocus = false;
        ctrl.$hasVisited = true;
      });

      elm.closest('form').on('submit', function () {
        elm.addClass('has-visited');

        scope.$apply(function () {
          ctrl.hasFocus = false;
          ctrl.hasVisited = true;
        });
      });
    }
  };
};
app.directive('input', blurFocusDirective);
app.directive('select', blurFocusDirective);

2

Es könnte für Sie funktionieren, eine benutzerdefinierte Direktive zu schreiben, die die Javascript-Methode blur () umschließt (und beim Auslösen eine Validierungsfunktion ausführt). Es gibt ein Angular-Problem mit einem Beispiel (sowie eine generische Direktive, die an andere Ereignisse gebunden werden kann, die von Angular nicht nativ unterstützt werden):

https://github.com/angular/angular.js/issues/1277

Wenn Sie diesen Weg nicht gehen möchten, besteht Ihre andere Option darin, $ watch auf dem Feld einzurichten und erneut eine Validierung auszulösen, wenn das Feld ausgefüllt ist.


2

Um die gegebenen Antworten weiter zu erfassen, können Sie die Eingabe-Kennzeichnung vereinfachen, indem Sie CSS3-Pseudoklassen verwenden und besuchte Felder nur mit einer Klasse markieren, um die Anzeige von Validierungsfehlern zu verzögern, bis der Benutzer den Fokus auf das Feld verloren hat:

(Beispiel erfordert jQuery)

JavaScript

module = angular.module('app.directives', []);
module.directive('lateValidateForm', function () {
    return {
        restrict: 'AC',
        link: function (scope, element, attrs) {
            $inputs = element.find('input, select, textarea');

            $inputs.on('blur', function () {
                $(this).addClass('has-visited');
            });

            element.on('submit', function () {
                $inputs.addClass('has-visited');
            });
        }
    };
});

CSS

input.has-visited:not(:focus):required:invalid,
textarea.has-visited:not(:focus):required:invalid,
select.has-visited:not(:focus):required:invalid {
  color: #b94a48;
  border-color: #ee5f5b;
}

HTML

<form late-validate-form name="userForm">
  <input type="email" name="email" required />
</form>

2

basierend auf @nicolas Antwort .. Reines CSS sollte der Trick sein, es wird nur die Fehlermeldung bei Unschärfe angezeigt

<input type="email" id="input-email" required
               placeholder="Email address" class="form-control" name="email"
               ng-model="userData.email">
        <p ng-show="form.email.$error.email" class="bg-danger">This is not a valid email.</p>

CSS

.ng-invalid:focus ~ .bg-danger {
     display:none;
}

Dies ist gut, aber die Fehlermeldung verschwindet, wenn der Benutzer in das Feld zurückklickt, was nicht ideal ist.
Bennett McElwee

2

Hier ist ein Beispiel mit ng-messages (verfügbar in Winkel 1.3) und einer benutzerdefinierten Direktive.

Die Validierungsnachricht wird zum ersten Mal bei Unschärfe angezeigt, wenn der Benutzer das Eingabefeld verlässt. Wenn er den Wert korrigiert, wird die Validierungsnachricht sofort entfernt (nicht mehr bei Unschärfe).

JavaScript

myApp.directive("validateOnBlur", [function() {
    var ddo = {
        restrict: "A",
        require: "ngModel",
        scope: {},
        link: function(scope, element, attrs, modelCtrl) {
            element.on('blur', function () {
                modelCtrl.$showValidationMessage = modelCtrl.$dirty;
                scope.$apply();
            });
        }
    };
    return ddo;
}]);

HTML

<form name="person">
    <input type="text" ng-model="item.firstName" name="firstName" 
        ng-minlength="3" ng-maxlength="20" validate-on-blur required />
    <div ng-show="person.firstName.$showValidationMessage" ng-messages="person.firstName.$error">
        <span ng-message="required">name is required</span>
        <span ng-message="minlength">name is too short</span>
        <span ng-message="maxlength">name is too long</span>
    </div>
</form>

PS. Vergessen Sie nicht, ngMessages herunterzuladen und in Ihr Modul aufzunehmen:

var myApp = angular.module('myApp', ['ngMessages']);

1

ng-model-options in AngularJS 1.3 (Beta zum Zeitpunkt dieses Schreibens) ist dokumentiert, um {updateOn: 'blur'} zu unterstützen. Bei früheren Versionen hat für mich Folgendes funktioniert:

myApp.directive('myForm', function() {
  return {
    require: 'form',
    link: function(scope, element, attrs, formController) {
      scope.validate = function(name) {
        formController[name].isInvalid
            = formController[name].$invalid;
      };
    }
  };
});

Mit einer Vorlage wie dieser:

<form name="myForm" novalidate="novalidate" data-my-form="">
<input type="email" name="eMail" required="required" ng-blur="validate('eMail')" />
<span ng-show="myForm.eMail.isInvalid">Please enter a valid e-mail address.</span>
<button type="submit">Submit Form</button>
</form>

1

Feldstatus $ touch verwenden Das Feld wurde dafür berührt, wie im folgenden Beispiel gezeigt.

<div ng-show="formName.firstName.$touched && formName.firstName.$error.required">
    You must enter a value
</div>

0

Sie können die CSS-Klasse mit Fehlerfehlern dynamisch festlegen (vorausgesetzt, Sie verwenden Bootstrap), indem Sie die Klasse ng und eine Eigenschaft für den Bereich des zugeordneten Controllers verwenden:

plunkr: http://plnkr.co/edit/HYDlaTNThZE02VqXrUCH?p=info

HTML:

<div ng-class="{'has-error': badEmailAddress}">
    <input type="email" class="form-control" id="email" name="email"
        ng-model="email" 
        ng-blur="emailBlurred(email.$valid)">
</div>

Regler:

$scope.badEmailAddress = false;

$scope.emailBlurred = function (isValid) {
    $scope.badEmailAddress = !isValid;
};

0

Wenn Sie Bootstrap 3 und lesscss verwenden, können Sie die Validierung bei Unschärfe mit dem folgenden weniger Snippet aktivieren:

:focus ~ .form-control-feedback.glyphicon-ok {
  display:none;
}

:focus ~ .form-control-feedback.glyphicon-remove {
  display:none;
}

.has-feedback > :focus {
  & {
    .form-control-focus();
  }
}

0

Ich habe eine Richtlinie verwendet. Hier ist der Code:

app.directive('onBlurVal', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs, controller) {

            element.on('focus', function () {
                element.next().removeClass('has-visited');
                element.next().addClass('has-focus');
            });

            element.on('blur', function () {

                element.next().removeClass('has-focus');
                element.next().addClass('has-visited');
            });
        }
    }
})

Alle meine Eingabesteuerelemente haben ein span-Element als nächstes Element, in dem meine Validierungsnachricht angezeigt wird, und daher wird die Anweisung als Attribut zu jedem Eingabesteuerelement hinzugefügt.

Ich habe auch (optional) .has-focus und habe die CSS-Klasse in meiner CSS-Datei besucht, auf die in der Direktive verwiesen wird.

HINWEIS: Denken Sie daran, 'on-blur-val' genau auf diese Weise zu Ihrer Eingabesteuerung ohne die Apostrophe hinzuzufügen


0

Mit ng-focus können Sie Ihr Ziel erreichen. Sie müssen ng-focus in Ihrem Eingabefeld angeben. Und während Sie Ihre ng-show-Derivate schreiben, müssen Sie auch eine Logik schreiben, die nicht gleich ist. Wie der folgende Code:

<input type="text" class="form-control" name="inputPhone" ng-model="demo.phoneNumber" required ng-focus> <div ng-show="demoForm.inputPhone.$dirty && demoForm.inputPhone.$invalid && !demoForm.inputPhone.$focused"></div>


0

Wir können Onfocus- und Onblur-Funktionen verwenden. Wäre einfach und am besten.

<body ng-app="formExample">
  <div ng-controller="ExampleController">
  <form novalidate class="css-form">
    Name: <input type="text" ng-model="user.name" ng-focus="onFocusName='focusOn'" ng-blur="onFocusName=''" ng-class="onFocusName" required /><br />
    E-mail: <input type="email" ng-model="user.email" ng-focus="onFocusEmail='focusOn'" ng-blur="onFocusEmail=''" ng-class="onFocusEmail" required /><br />
  </form>
</div>

<style type="text/css">
 .css-form input.ng-invalid.ng-touched {
    border: 1px solid #FF0000;
    background:#FF0000;
   }
 .css-form input.focusOn.ng-invalid {
    border: 1px solid #000000;
    background:#FFFFFF;
 }
</style>

Versuch es hier:

http://plnkr.co/edit/NKCmyru3knQiShFZ96tp?p=preview

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.