Dzięki AngularJS mogę użyć ng-pristine
lub ng-dirty
wykryć, czy użytkownik wszedł na pole. Jednak chcę przeprowadzić walidację po stronie klienta dopiero po opuszczeniu przez użytkownika obszaru pola. Dzieje się tak, ponieważ gdy użytkownik wejdzie w pole, takie jak e-mail lub telefon, zawsze otrzyma komunikat o błędzie, dopóki nie zakończy wpisywania pełnego adresu e-mail, a to nie jest optymalne dla użytkownika.
AKTUALIZACJA:
Angular jest teraz dostarczany z niestandardowym zdarzeniem rozmycia: https://docs.angularjs.org/api/ng/directive/ngBlur
Odpowiedzi:
Angular 1.3 ma teraz opcje ng-model-options i możesz ustawić tę opcję
{ 'updateOn': 'blur'}
na przykład, a nawet możesz odrzucić, gdy użycie jest albo zbyt szybkie, albo chcesz zaoszczędzić kilka kosztownych operacji DOM (takich jak pisanie modelu do wielu miejsc DOM i nie chcesz, aby cykl podsumowania $ występował przy każdym naciśnięciu klawisza)https://docs.angularjs.org/guide/forms#custom-triggers i https://docs.angularjs.org/guide/forms#non-immediate-debounced-model-updates
I odbić
źródło
ng-change
zdarzenia, zanim użytkownik opuści pole. Na przykład w moim przypadku żądam nowych danych z mojego API, gdy tylko pole wejściowe jest prawidłowe, ale nie chcę wyświetlać komunikatu o błędzie, gdy jest on nieprawidłowy - chcę to zrobić tylko wtedy, gdy jest nieważne i wystąpiło rozmycie.1.3.0 rc-3
i nie odpalachange
dopókiblur
, sprawdź to: plnkr.co/edit/RivVU3r7xfHO1hUybqMu?p=previewOd wersji 1.3.0 można to łatwo zrobić
$touched
, co jest prawdą po opuszczeniu pola przez użytkownika.<p ng-show="form.field.$touched && form.field.$invalid">Error</p>
https://docs.angularjs.org/api/ng/type/ngModel.NgModelController
źródło
updateOn: 'default'
oznacza, że dla danych wejściowych, klawisza w górę i dla zaznaczeń, przy zmianieRozwiązałem to, rozszerzając to, co zasugerował @jlmcdonald. Stworzyłem dyrektywę, która zostanie automatycznie zastosowana do wszystkich danych wejściowych i wybierz elementy:
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);
Spowoduje to dodanie
has-focus
ihas-visited
klasy do różnych elementów, gdy użytkownik skupia się / odwiedza elementy. Następnie możesz dodać te klasy do reguł CSS, aby wyświetlić błędy walidacji:input.has-visited.ng-invalid:not(.has-focus) { background-color: #ffeeee; }
Działa to dobrze, ponieważ elementy nadal mają nieprawidłowe właściwości itp., Ale CSS można wykorzystać, aby zapewnić użytkownikowi lepsze wrażenia.
źródło
formName.inputName.$dirty
. Sugerowałbym edycję dyrektywy, aby napisać podobne wartości logiczneformName.inputName.$focused
, zamiast używać nazw klas do rozmycia i wartości logicznych do walidacji.Udało mi się to zrobić za pomocą całkiem prostego fragmentu CSS. Wymaga to, aby komunikaty o błędach były rodzeństwem danych wejściowych, do których się odnoszą, i aby miały klasę
error
.:focus ~ .error { display:none; }
Po spełnieniu tych dwóch wymagań spowoduje to ukrycie wszelkich komunikatów o błędach związanych z aktywnym polem wejściowym, co moim zdaniem i tak powinno robić angularjs. Wygląda na przeoczenie.
źródło
Wydaje się, że jest to standardowo realizowane w nowszych wersjach angular.
Klasy ng-untouched i ng-touch są ustawiane odpowiednio przed i po tym, jak użytkownik skupił się na walidowanym elemencie.
CSS
input.ng-touched.ng-invalid { border-color: red; }
źródło
Odnośnie rozwiązania @ lambinator ... Otrzymałem następujący błąd w angular.js 1.2.4:
Nie jestem pewien, czy zrobiłem coś źle, czy jest to zmiana w Angular, ale usunięcie
scope.$apply
instrukcji rozwiązało problem, a klasy / stany są nadal aktualizowane.Jeśli również widzisz ten błąd, spróbuj:
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);
źródło
Możesz napisać własną dyrektywę, która otacza metodę javascript blur () (i uruchamia funkcję walidacji po uruchomieniu); istnieje problem z Angularem, który ma przykładowy (a także ogólną dyrektywę, która może wiązać się z innymi zdarzeniami, które nie są natywnie obsługiwane przez Angular):
https://github.com/angular/angular.js/issues/1277
Jeśli nie chcesz jechać tą trasą, inną opcją byłoby ustawienie $ watch na polu, ponownie uruchamiając walidację, gdy pole zostanie wypełnione.
źródło
Aby dalej podchwycić podane odpowiedzi, możesz uprościć tagowanie danych wejściowych, używając pseudoklas CSS3 i oznaczając odwiedzane pola tylko klasą, aby opóźnić wyświetlanie błędów walidacji, aż użytkownik straci koncentrację na polu:
(Przykład wymaga 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>
źródło
na podstawie odpowiedzi @nicolas .. Czysty CSS powinien być sztuczką, pokaże tylko komunikat błędu przy rozmyciu
<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; }
źródło
Oto przykład użycia ng-messages (dostępne w angular 1.3) i niestandardowej dyrektywy.
Komunikat walidacyjny jest wyświetlany przy rozmyciu po raz pierwszy, gdy użytkownik opuszcza pole wejściowe, ale kiedy koryguje wartość, komunikat walidacji jest natychmiast usuwany (już nie przy rozmyciu).
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. Nie zapomnij pobrać i dołączyć ngMessages do swojego modułu:
var myApp = angular.module('myApp', ['ngMessages']);
źródło
Udokumentowano, że ng-model-options w AngularJS 1.3 (beta w chwili pisania tego tekstu) obsługuje {updateOn: 'blur'}. W przypadku wcześniejszych wersji działało dla mnie coś takiego:
myApp.directive('myForm', function() { return { require: 'form', link: function(scope, element, attrs, formController) { scope.validate = function(name) { formController[name].isInvalid = formController[name].$invalid; }; } }; });
Z takim szablonem:
<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>
źródło
Użyj stanu pola $ touched Pole zostało w tym celu dotknięte, jak pokazano na poniższym przykładzie.
<div ng-show="formName.firstName.$touched && formName.firstName.$error.required"> You must enter a value </div>
źródło
Możesz dynamicznie ustawić klasę css has-error (zakładając, że używasz bootstrap), używając ng-class i właściwości w zakresie powiązanego kontrolera:
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>
Kontroler:
$scope.badEmailAddress = false; $scope.emailBlurred = function (isValid) { $scope.badEmailAddress = !isValid; };
źródło
Jeśli używasz bootstrap 3 i lesscss, możesz włączyć weryfikację rozmycia za pomocą następującego mniejszego fragmentu:
:focus ~ .form-control-feedback.glyphicon-ok { display:none; } :focus ~ .form-control-feedback.glyphicon-remove { display:none; } .has-feedback > :focus { & { .form-control-focus(); } }
źródło
out Użyłem dyrektywy. Oto kod:
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'); }); } } })
Cała moja kontrolka wejściowa ma element span jako następny element, w którym jest wyświetlany mój komunikat walidacji, a zatem dyrektywa jako atrybut jest dodawana do każdej kontrolki wejściowej.
Mam również (opcjonalnie) .has-focus i odwiedził klasę css w moim pliku css, do którego odwołuje się dyrektywa.
UWAGA: pamiętaj, aby dodać „on-blur-val” dokładnie w ten sposób do kontrolki wejścia bez apostrofów
źródło
Używając ng-focus , możesz osiągnąć swój cel. musisz podać ng-focus w swoim polu wprowadzania. A pisząc swoje pochodne ng-show, musisz napisać logikę, która nie jest równa. Jak poniższy kod:
<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>
źródło
Możemy korzystać z funkcji onfocus i onblur. Byłoby proste i najlepsze.
<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>
Spróbuj tutaj:
http://plnkr.co/edit/NKCmyru3knQiShFZ96tp?p=preview
źródło