Проверять поля после того, как пользователь покинул поле

С помощью AngularJS я могу использовать ng-pristine или ng-dirty, чтобы определить, введен ли пользователь в поле. Тем не менее, я хочу сделать проверку на стороне клиента только после того, как пользователь покинул поле. Это связано с тем, что, когда пользователь входит в поле, такое как электронная почта или телефон, они всегда будут получать ошибки, пока они не завершат заполнение полного сообщения электронной почты, и это не оптимальный пользовательский интерфейс.

Пример


UPDATE:

Angular теперь поставляется с настраиваемым событием размытия: https://docs.angularjs.org/api/ng/directive/ngBlur

Ответ 1

Angular 1.3 теперь имеет параметры ng-model, и вы можете, например, установить параметр { 'updateOn': 'blur'}, и вы даже можете отбросить, когда использование будет слишком набирать слишком быстро, или вы хотите сохранить несколько дорогостоящие операции DOM (например, запись модели в несколько мест DOM, и вы не хотите, чтобы на каждом нажатии клавиши выполнялся цикл $digest)

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

По умолчанию любое изменение содержимого приведет к обновлению модели и проверка формы. Вы можете переопределить это поведение, используя Директива ngModelOptions связывается только с указанным списком событий. То есть ng-model-options = "{updateOn: 'blur'}" будет обновлять и проверять только после того, как управление теряет фокус. Вы можете установить несколько событий, используя Список разделенных пробелами. То есть ng-model-options = "{updateOn: 'mousedown blur '}"

И debounce

Вы можете задержать обновление/проверку модели с помощью ключа debounce с директивой ngModelOptions. Эта задержка будет также применяться к парсеров, валидаторов и флагов модели, таких как $грязный или $чистый.

т.е. ng-model-options = "{debounce: 500}" будет ждать полсекунды поскольку последнее изменение содержимого перед запуском обновления модели и проверка формы.

Ответ 2

Из версии 1.3.0 это можно легко сделать с помощью $touched, который является истинным после того, как пользователь покинул поле.

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

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

Ответ 3

Я решил это, расширив то, что предложил @jlmcdonald. Я создал директиву, которая будет автоматически применяться ко всем элементам ввода и выбора:

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);

Это добавит классы has-focus и has-visited к различным элементам, поскольку пользователь фокусирует/посещает элементы. Затем вы можете добавить эти классы в свои правила CSS, чтобы показать ошибки проверки:

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

Это хорошо работает в том, что элементы по-прежнему получают $недопустимые свойства и т.д., но CSS можно использовать, чтобы дать пользователю лучший опыт.

Ответ 4

Мне удалось сделать это с помощью довольно простого фрагмента CSS. Это требует, чтобы сообщения об ошибках были братьями и сестрами ввода, к которому они относятся, и что у них есть класс error.

:focus ~ .error {
    display:none;
}

После выполнения этих двух требований это скроет любое сообщение об ошибке, связанное с целенаправленным полем ввода, что, по-моему, должно быть в любом случае. Похоже на надзор.

Ответ 5

Что касается решения @lambinator... Я получил следующую ошибку в angular.js 1.2.4:

Ошибка: [$ rootScope: inprog] $digest уже выполняется

Я не уверен, что я сделал что-то неправильно или это изменение в Angular, но удаление операторов scope.$apply разрешило проблему, а состояния классов/состояний все еще обновляются.

Если вы также видите эту ошибку, попробуйте следующее:

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);

Ответ 6

Это, по-видимому, реализовано как стандарт в новых версиях angular.

Классы ng-нетронутые и ng-touched установлены соответственно до и после того, как пользователь сосредоточился на проверенном элементе.

CSS

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

Ответ 7

Может возникнуть необходимость написать специальную директиву, которая обертывает метод javascript blur() (и запускает функцию проверки при срабатывании); существует проблема Angular, которая имеет образец один (а также общую директиву, которая может связываться с другими событиями, не поддерживаемыми изначально Angular):

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

Если вы не хотите идти по этому маршруту, другим вариантом будет установка $watch в поле, снова запускающее проверку, когда поле будет заполнено.

Ответ 8

Чтобы получить дополнительные ответы на эти ответы, вы можете упростить ввод тегов с помощью псевдоклассов CSS3 и только пометить посещенные поля классом, чтобы задержать отображение ошибок проверки до тех пор, пока пользователь не потеряет фокус на поле:

(Пример требует 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>

Ответ 9

на основе @nicolas answer.. Чистый CSS должен трюк, он будет показывать сообщение об ошибке при размытии

<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;
}

Ответ 10

Вот пример использования ng-сообщений (доступно в angular 1.3) и пользовательской директивы.

Сообщение о валидации отображается при размытии в первый раз, когда пользователь покидает поле ввода, но когда он исправляет это значение, сообщение проверки немедленно удаляется (а не размывается).

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. Не забудьте загрузить и включить ngMessages в свой модуль:

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

Ответ 11

ng-model-options в AngularJS 1.3 (бета на момент написания этой статьи) документируется для поддержки {updateOn: 'blur'}. Для более ранних версий для меня работало что-то вроде следующего:

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

С шаблоном, подобным этому:

<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>

Ответ 12

Вы можете динамически установить класс css has-error (при условии, что вы используете загрузку), используя ng-класс и свойство в области действия связанного контроллера:

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>

Контроллер:

$scope.badEmailAddress = false;

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

Ответ 13

Если вы используете bootstrap 3 и lesscss, вы можете включить проверку blur с помощью следующего менее фрагмента:

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

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

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

Ответ 14

outI использовал директиву. Вот код:

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');
            });
        }
    }
})

Все мое управление ввода имеет элемент span в качестве следующего элемента, в котором отображается мое сообщение проверки, и поэтому директива как атрибут добавляется к каждому элементу управления вводом.

У меня также есть (необязательный).has-focus и has-visited css-класс в моем файле css, который вы видите ссылкой в ​​директиве.

ПРИМЕЧАНИЕ: не забудьте добавить "on-blur-val" именно таким образом к вашему вводу без апострофов

Ответ 15

Используя ng-focus, вы можете достичь своей цели. вам необходимо предоставить ng-focus в поле ввода. И при написании своих производных ng-show вы должны написать логику, не равную тоже. Как приведенный ниже код:

<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>

Ответ 16

Мы можем использовать функции onfocus и onblur. Было бы просто и лучше.

<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>

Попробуйте здесь:

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

Ответ 17

Использовать полевое состояние $коснулось. Поле коснулось для этого, как показано ниже.

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