사용자가 필드를 떠난 후 필드 유효성 검사


92

AngularJS를 사용 하면 사용자가 필드에 입력했는지 여부를 사용 ng-pristine하거나 ng-dirty감지 할 수 있습니다 . 그러나 사용자가 필드 영역을 떠난 후에 만 ​​클라이언트 측 유효성 검사를 수행하고 싶습니다. 이는 사용자가 전자 메일 또는 전화와 같은 필드에 입력 할 때 전체 전자 메일 입력을 완료 할 때까지 항상 오류가 발생하며 이는 최적의 사용자 환경이 아니기 때문입니다.


최신 정보:

Angular는 이제 커스텀 블러 이벤트와 함께 제공됩니다 : https://docs.angularjs.org/api/ng/directive/ngBlur


3
나는이 ... 뭔가 AngularJS와 지원해야이라고 생각
CSG는

아마도. 기본 제공 양식 유효성 검사는 꽤 잘 작동하므로이 기본 제공 여부를 알 수 없습니다. 결국 대부분의 사용 사례에서는 Angular가 즉시 유효성을 검사하기를 원합니다. 즉, 숫자 필드에서 사용자가 문자를 입력하기 시작하면 양식이 즉시 무효화되기를 원합니다.
mcranston18 2014

11
흐림에 대한 검증은 15 년 이후로 일반적입니다 ...
Olivvv

답변:


75

Angular 1.3에는 이제 ng-model-options가 있으며 { 'updateOn': 'blur'}예를 들어 옵션을 설정할 수 있으며 사용이 너무 빨리 입력하거나 값 비싼 DOM 작업을 저장하려는 경우 (모델 작성과 같은) 디 바운스 할 수도 있습니다. 여러 DOM 장소로 이동하고 모든 키를 누를 때마다 $ digest 사이클이 발생하는 것을 원하지 않습니다)

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

기본적으로 콘텐츠를 변경하면 모델 업데이트 및 양식 유효성 검사가 트리거됩니다. ngModelOptions 지시문을 사용하여이 동작을 재정 의하여 지정된 이벤트 목록에만 바인딩 할 수 있습니다. Ie ng-model-options = "{updateOn : 'blur'}"는 컨트롤이 포커스를 잃은 후에 만 ​​업데이트하고 유효성을 검사합니다. 공백으로 구분 된 목록을 사용하여 여러 이벤트를 설정할 수 있습니다. Ie ng-model-options = "{updateOn : '마우스 다운 흐림'}"

그리고 디 바운스

ngModelOptions 지시문과 함께 debounce 키를 사용하여 모델 업데이트 / 검증을 지연 할 수 있습니다. 이 지연은 파서, 유효성 검사기 및 $ dirty 또는 $ pristine과 같은 모델 플래그에도 적용됩니다.

Ie ng-model-options = "{debounce : 500}"는 모델 업데이트 및 양식 유효성 검사를 트리거하기 전에 마지막 콘텐츠 변경 이후 0.5 초 동안 기다립니다.


2
대부분의 경우 ng-change사용자가 필드를 떠나기 전에 이벤트 를 받기를 원하기 때문에 문제가 해결되지 않습니다 . 예를 들어, 필자의 경우 입력 필드가 유효하자마자 API에서 새 데이터를 요청하지만 유효하지 않은 즉시 오류 메시지를 표시하고 싶지 않습니다. 유효하지 않고 흐림 이벤트가 발생했습니다.
Tom

@ 톰 내가 테스트하고있어 1.3.0 rc-3하고 화재하지 않습니다 change때까지 blur:이 확인 plnkr.co/edit/RivVU3r7xfHO1hUybqMu?p=preview
길 베이츠

이것은 정말로 받아 들여지는 최고의 대답이어야합니다. 단일 속성을 추가 할 수 있는데 왜 지시문을 추가합니까?
Dan Hulton 2015 년

92

버전 1.3.0부터는을 사용하여 쉽게 수행 할 수 있으며 $touched, 이는 사용자가 필드를 떠난 후에 적용됩니다.

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

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


1
각 키업 후에도 여전히 유효성 검사를 실행하지 않습니까? OP는 사용자가 필드를 떠난 후에 만 ​​유효성 검사를하고 싶다고 말했습니다.
comecme 2015

@comecme 예, 그렇습니다. 기본 ng-model-options는 updateOn: 'default'입력,
키업

5
하지만 여기서 큰 결점은 현장으로 돌아 오면 동일한 검증 경험이 없다는 것입니다. 이미 터치로 설정되어 있기 때문에 모든 키 입력에 대해 유효성을 검사하는 원점으로 돌아 왔습니다. 나는 이것이 너무 많은 찬성표를 가지고 있다는 것에 놀랐습니다.
dudewad

3
@dudewad 맞지만 UX 현명하게 원하는 동작이라고 생각합니다. 잘못된 필드로 돌아 오면 첫 글자를 입력 할 때까지가 아니라 값이 유효 할 때까지 오류 메시지가 지속되어야합니다.
danbars

@dudewad 사용자가 필드를 처음 채운 후 유효하지 않은 필드를 이미 알고있는 경우 각 프레스에서 유효성을 검사하는 데 도움이되지 않을까요? 필드가 유효하지 않다는 것을 알게되면 필드가 유효한시기를 신속하게 알고 싶어 할 가능성이 높으며 각 키를 누를 때마다 유효성을 검사하면 해당 프로세스의 속도가 빨라질 수 있습니까?
Alan Dunning 2016 년

32

@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-focushas-visited클래스 가 추가됩니다 . 그런 다음 이러한 클래스를 CSS 규칙에 추가하여 유효성 검사 오류를 표시 할 수 있습니다.

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

이것은 요소가 여전히 $ invalid 속성 등을 얻는다는 점에서 잘 작동하지만 CSS를 사용하여 사용자에게 더 나은 경험을 제공 할 수 있습니다.


2
단순히 'ngModel'대신 '? ngModel'이 필요한 이유는 무엇입니까? ngModel이 있어야한다는 것을 이해하지만 왜 물음표가 필요합니까?
Noremac 2013

2
아이디어 주셔서 감사합니다. jQuery가 필요하다는 것을 지적해야합니다 (jql에서 .closest ()를 볼 수 없다고 생각합니다).
iandotkelly 2013

1
모든 <input> 요소가 ngModel에서 지원되는 것은 아닙니다 (예 : input type = submit). ? 이를 지원하는 요소에서만 ngModel이 필요합니다.
chmanie 2013

5
솔직히 말해서 .NET과 같은 입력 필드 상태를 설정하는 각도 방식에서 벗어나면 안됩니다 formName.inputName.$dirty. formName.inputName.$focused블러에 클래스 이름을 사용하고 유효성 검사를 위해 부울을 사용하는 대신 지시문을 편집하여 유사한 부울을 작성하는 것이 좋습니다 .
Tom

17

저는 아주 간단한 CSS로 이것을 할 수있었습니다. 이렇게하려면 오류 메시지가 관련된 입력의 형제 여야하고 error.

:focus ~ .error {
    display:none;
}

이 두 가지 요구 사항을 충족하면 집중된 입력 필드와 관련된 오류 메시지가 숨겨집니다. angularjs가 어쨌든해야 할 일이라고 생각합니다. 감독처럼 보입니다.


2
아. 이것은 현명한 방법입니다. 나는 그것을하기 위해 자바 스크립트를 작성하는 것보다 이것을 선호합니다.
데크

5
이 접근 방식의 단점은 누군가가 오류를 수정할 때 이상적이지 않은 오류가 더 이상 표시되지 않는다는 것입니다. 이상은 블러가 나타날 때까지 오류가 표시되지 않지만 수정 될 때까지 사라지지 않는 것입니다.
Chris Nicola

4

이것은 angular의 최신 버전에서 표준으로 구현 된 것 같습니다.

ng-untouchedng-touched 클래스 는 사용자가 검증 된 요소에 초점을 맞추기 전과 후에 각각 설정됩니다.

CSS

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

4

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

2

javascript blur () 메서드를 래핑하고 트리거 될 때 유효성 검사 함수를 실행하는 사용자 지정 지시문을 작성하는 것이 좋습니다. 샘플 1이있는 Angular 문제가 있습니다 (Angular에서 기본적으로 지원되지 않는 다른 이벤트에 바인딩 할 수있는 일반 지시문 포함) :

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

해당 경로로 이동하지 않으려면 다른 옵션은 필드에 $ watch를 설정하고 필드가 채워지면 유효성 검사를 다시 트리거하는 것입니다.


2

주어진 답변을 더 선택하기 위해 CSS3 의사 클래스를 사용하고 방문한 필드 만 클래스로 표시하여 사용자가 필드에 초점을 잃을 때까지 유효성 검사 오류 표시를 지연하여 입력 태그 지정을 단순화 할 수 있습니다.

(예제에는 jQuery가 필요합니다)

자바 스크립트

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

@nicolas 대답을 기반으로합니다. 순수한 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;
}

이것은 좋지만 사용자가 필드를 다시 클릭하면 오류 메시지가 사라 지므로 이상적이지 않습니다.
Bennett McElwee 2014 년

2

다음은 ng-messages (angular 1.3에서 사용 가능) 및 사용자 지정 지시문을 사용하는 예입니다.

사용자가 입력 필드를 처음 떠날 때 유효성 검사 메시지가 흐리게 표시되지만 값을 수정하면 유효성 검사 메시지가 즉시 제거됩니다 (더 이상 흐리게 표시되지 않음).

자바 스크립트

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>

추신. 모듈에 ngMessages를 다운로드하고 포함하는 것을 잊지 마십시오.

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

1

AngularJS 1.3의 ng-model-options (이 글을 쓰는 시점에서 베타 버전)는 {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>

1

Use field state $ touched 필드는 아래 예제와 같이이를 위해 터치되었습니다.

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

0

ng-class 및 관련 컨트롤러 범위의 속성을 사용하여 has-error css 클래스 (부트 스트랩을 사용한다고 가정)를 동적으로 설정할 수 있습니다.

플 런커 : 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;
};

0

부트 스트랩 3 및 lesscss를 사용하는 경우 다음 less 스 니펫으로 블러 유효성 검사를 활성화 할 수 있습니다.

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

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

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

0

out 지시문을 사용했습니다. 다음은 코드입니다.

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'을 추가해야합니다.


0

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>


0

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.