Xác thực các trường sau khi người dùng rời khỏi trường


92

Với AngularJS, tôi có thể sử dụng ng-pristinehoặc ng-dirtyđể phát hiện xem người dùng đã vào trường chưa. Tuy nhiên, tôi chỉ muốn xác thực phía máy khách sau khi người dùng đã rời khỏi khu vực trường. Điều này là do khi người dùng nhập vào một trường như e-mail hoặc điện thoại, họ sẽ luôn gặp lỗi cho đến khi hoàn thành việc nhập đầy đủ e-mail của mình và đây không phải là trải nghiệm người dùng tối ưu.

Thí dụ


CẬP NHẬT:

Angular hiện giao hàng với một sự kiện làm mờ tùy chỉnh: https://docs.angularjs.org/api/ng/directive/ngBlur


3
Tôi đoán rằng đây là thứ gì đó mà anglejs nên hỗ trợ ...
csg

Có lẽ. Xác thực trong biểu mẫu được xây dựng hoạt động khá tốt mà tôi không biết liệu tôi có muốn nó được tích hợp sẵn hay không. Sau cùng, hầu hết các trường hợp sử dụng tôi muốn Angular xác thực ngay lập tức. tức là trong một trường số, tôi muốn biểu mẫu vô hiệu ngay lập tức nếu người dùng bắt đầu nhập các chữ cái.
mcranston18

11
xác nhận vào làm mờ được phổ biến kể từ 15 năm ...
Olivvv

Câu trả lời:


75

Angular 1.3 hiện có ng-model-options và bạn có thể đặt tùy chọn thành { 'updateOn': 'blur'}ví dụ, và thậm chí bạn có thể gỡ lỗi khi sử dụng gõ quá nhanh hoặc bạn muốn tiết kiệm một vài thao tác DOM tốn kém (như viết mô hình đến nhiều địa điểm DOM và bạn không muốn chu kỳ thông báo $ diễn ra trên mọi phím xuống)

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

Theo mặc định, bất kỳ thay đổi nào đối với nội dung sẽ kích hoạt cập nhật mô hình và xác thực biểu mẫu. Bạn có thể ghi đè hành vi này bằng cách sử dụng chỉ thị ngModelOptions để chỉ liên kết với danh sách sự kiện được chỉ định. Tức là ng-model-options = "{updateOn: 'dim'}" sẽ chỉ cập nhật và xác thực sau khi điều khiển mất tiêu điểm. Bạn có thể đặt một số sự kiện bằng cách sử dụng danh sách được phân cách bằng dấu cách. Tức là ng-model-options = "{updateOn: 'mousedown dim'}"

Và sự hủy hoại

Bạn có thể trì hoãn việc cập nhật / xác thực mô hình bằng cách sử dụng phím gỡ lỗi với lệnh ngModelOptions. Sự chậm trễ này cũng sẽ áp dụng cho trình phân tích cú pháp, trình xác thực và cờ mô hình như $ dirty hoặc $ virgin.

Tức là ng-model-options = "{debounce: 500}" sẽ đợi nửa giây kể từ lần thay đổi nội dung cuối cùng trước khi kích hoạt cập nhật mô hình và xác thực biểu mẫu.


2
Trong hầu hết các trường hợp, điều này không giải quyết được sự cố, vì bạn có thể vẫn muốn nhận ng-changecác sự kiện trước khi người dùng rời khỏi trường. Ví dụ: trong trường hợp của tôi, tôi yêu cầu dữ liệu mới từ API của mình ngay khi trường đầu vào hợp lệ, nhưng tôi không muốn hiển thị thông báo lỗi ngay khi nó không hợp lệ - tôi chỉ muốn làm điều này khi nó không hợp lệ và sự kiện mờ đã xảy ra.
Tom,

@ Tom Tôi đang thử nghiệm 1.3.0 rc-3và nó không lửa changecho đến khi blur, kiểm tra này: plnkr.co/edit/RivVU3r7xfHO1hUybqMu?p=preview
Gill Bates

Đây thực sự phải là câu trả lời được chấp nhận hàng đầu. Tại sao phải thêm một chỉ thị, khi bạn có thể thêm một thuộc tính?
Dan Hulton

92

Từ phiên bản 1.3.0, điều này có thể dễ dàng được thực hiện với $touched, điều này đúng sau khi người dùng rời khỏi sân.

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

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


1
Điều đó sẽ không thực hiện xác thực sau mỗi lần gõ phím? OP cho biết anh ấy chỉ muốn xác thực sau khi người dùng đã rời khỏi trường.
comecme

@comecme có nó sẽ, những ng-mô hình tùy chọn mặc định là updateOn: 'default'có phương tiện, đối với nguyên liệu đầu vào, tăng trọng, và cho lựa chọn, về biến đổi
pocesar

5
Tuy nhiên, lỗ hổng lớn ở đây là bạn sẽ không có trải nghiệm xác thực tương tự nếu bạn quay lại sân. Bạn đang trở lại ô vuông một, nơi nó xác thực trên mọi lần nhấn phím, vì nó đã được đặt thành chạm. Tôi ngạc nhiên vì điều này nhận được rất nhiều ủng hộ.
dudewad

3
@dudewad đúng, nhưng tôi nghĩ đó là hành vi mong muốn của UX - nếu bạn quay lại trường không hợp lệ, thông báo lỗi sẽ tồn tại cho đến khi giá trị hợp lệ, không phải cho đến khi bạn nhập chữ cái đầu tiên.
danbars

@dudewad Nó có giúp người dùng xác thực trên mỗi lần nhấn sau khi họ đã biết một trường không hợp lệ sau lần đầu tiên họ điền vào không? Một khi họ biết trường không hợp lệ, có lẽ họ sẽ muốn nhanh chóng biết khi nào trường hợp lệ và việc xác thực trên mỗi lần nhấn phím có thể sẽ đẩy nhanh quá trình đó không?
Alan Dunning

32

Tôi đã giải quyết vấn đề này bằng cách mở rộng những gì @jlmcdonald đề xuất. Tôi đã tạo một chỉ thị sẽ tự động được áp dụng cho tất cả các phần tử đầu vào và chọn:

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

Điều này sẽ thêm has-focushas-visitedcác lớp cho các phần tử khác nhau khi người dùng tập trung / truy cập các phần tử. Sau đó, bạn có thể thêm các lớp này vào quy tắc CSS của mình để hiển thị lỗi xác thực:

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

Điều này hoạt động tốt trong đó các phần tử vẫn nhận được các thuộc tính $ không hợp lệ, v.v., nhưng CSS có thể được sử dụng để cung cấp cho người dùng trải nghiệm tốt hơn.


2
Tại sao lại yêu cầu '? NgModel' thay vì đơn giản là 'ngModel'? Tôi hiểu yêu cầu ngModel phải ở đó, nhưng tại sao lại có dấu chấm hỏi?
Noremac

2
Cảm ơn vì ý tưởng. Nên chỉ ra rằng nó yêu cầu jQuery (tôi nghĩ - không thể thấy .closest () trong jql).
iandotkelly

1
Không phải tất cả các phần tử <input> đều được ngModel hỗ trợ (ví dụ: input type = submit). Các ? chỉ yêu cầu ngModel trên các phần tử hỗ trợ nó.
chmanie

5
Thành thật mà nói, bạn không nên đi lệch khỏi cách thiết lập các trạng thái trường đầu vào như formName.inputName.$dirty. Tôi khuyên bạn nên chỉnh sửa chỉ thị để viết một boolean tương tự như vậy formName.inputName.$focused, thay vì sử dụng tên lớp để làm mờ và boolean để xác thực.
Tom,

17

Tôi đã quản lý để làm điều này với một chút CSS khá đơn giản. Điều này yêu cầu rằng các thông báo lỗi phải là anh chị em của đầu vào mà chúng liên quan đến và chúng có một lớp error.

:focus ~ .error {
    display:none;
}

Sau khi đáp ứng hai yêu cầu đó, thao tác này sẽ ẩn bất kỳ thông báo lỗi nào liên quan đến trường đầu vào được tập trung, điều mà tôi nghĩ rằng anglejs vẫn nên làm. Có vẻ như một sự giám sát.


2
Ahh. Đây là một cách thông minh để đi. Tôi thích điều này hơn viết javascript để làm điều đó.
boong

5
Nhược điểm của phương pháp này là khi ai đó đang sửa lỗi, lỗi sẽ không còn hiển thị, điều này không lý tưởng. Lý tưởng nhất là lỗi không hiển thị cho đến khi mờ nhưng không biến mất cho đến khi nó được sửa.
Chris Nicola,

4

Điều này dường như được thực hiện như là tiêu chuẩn trong các phiên bản góc cạnh mới hơn.

Các lớp ng-unsouchedng-touch được đặt tương ứng trước và sau khi người dùng đã tập trung vào phần tử đã được xác thực.

CSS

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

4

Về giải pháp của @ lambinator ... Tôi gặp lỗi sau trong angle.js 1.2.4:

Lỗi: [$ rootScope: inprog] $ thông báo đang được xử lý

Tôi không chắc liệu mình đã làm gì sai hay đây là một thay đổi trong Angular, nhưng việc xóa các scope.$applycâu lệnh đã giải quyết được sự cố và các lớp / trạng thái vẫn đang được cập nhật.

Nếu bạn cũng gặp lỗi này, hãy thử các cách sau:

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

Nó có thể phù hợp với bạn khi viết một chỉ thị tùy chỉnh bao bọc phương thức javascript mờ () (và chạy một hàm xác thực khi được kích hoạt); có một vấn đề Angular có một ví dụ mẫu (cũng như một chỉ thị chung có thể liên kết với các sự kiện khác không được hỗ trợ bởi Angular):

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

Nếu bạn không muốn đi theo con đường đó, tùy chọn khác của bạn sẽ là thiết lập $ watch trên trường, một lần nữa kích hoạt xác thực khi trường được điền.


2

Để tìm hiểu thêm về các câu trả lời đã cho, bạn có thể đơn giản hóa việc gắn thẻ đầu vào bằng cách sử dụng lớp giả CSS3 và chỉ đánh dấu các trường đã truy cập bằng một lớp để trì hoãn việc hiển thị lỗi xác thực cho đến khi người dùng mất tập trung vào trường:

(Ví dụ yêu cầu 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

dựa trên câu trả lời @nicolas .. Nên mẹo thuần túy CSS sẽ chỉ hiển thị thông báo lỗi khi bị mờ

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

Điều này là tốt, nhưng thông báo lỗi sẽ biến mất khi người dùng nhấp lại vào trường, điều này không lý tưởng.
Bennett McElwee

2

Đây là một ví dụ sử dụng ng-messages (có sẵn trong góc 1.3) và một chỉ thị tùy chỉnh.

Thông báo xác thực được hiển thị ở chế độ mờ trong lần đầu tiên người dùng rời khỏi trường nhập, nhưng khi anh ta sửa giá trị, thông báo xác thực sẽ bị xóa ngay lập tức (không bị mờ nữa).

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>

Tái bút. Đừng quên tải xuống và bao gồm ngMessages trong mô-đun của bạn:

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

1

ng-model-options trong AngularJS 1.3 (phiên bản beta tính đến thời điểm viết bài này) được ghi nhận để hỗ trợ {updateOn: 'fade'}. Đối với các phiên bản trước đó, một cái gì đó như sau phù hợp với tôi:

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

Với một mẫu như thế này:

<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

Sử dụng trạng thái trường $ đã chạm vào Trường đã được chạm cho điều này như thể hiện trong ví dụ dưới đây.

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

0

Bạn có thể đặt động lớp css có lỗi (giả sử bạn đang sử dụng bootstrap) bằng cách sử dụng ng-class và một thuộc tính trên phạm vi của bộ điều khiển được liên kết:

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>

Bộ điều khiển:

$scope.badEmailAddress = false;

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

0

Nếu bạn sử dụng bootstrap 3 và lesscss, bạn có thể bật xác thực mờ bằng đoạn mã less sau:

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

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

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

0

Tôi đã sử dụng một chỉ thị. Đây là mã:

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

Tất cả điều khiển đầu vào của tôi đều có phần tử span làm phần tử tiếp theo, đây là nơi hiển thị thông báo xác thực của tôi và do đó, chỉ thị dưới dạng thuộc tính được thêm vào mỗi điều khiển đầu vào.

Tôi cũng có (tùy chọn) .has-focus và lớp css đã ghé thăm trong tệp css của tôi mà bạn thấy đang được tham chiếu trong chỉ thị.

LƯU Ý: hãy nhớ thêm chính xác 'on-blur-val' theo cách này vào điều khiển đầu vào của bạn mà không có dấu nháy đơn


0

Bằng cách sử dụng ng-focus, bạn có thể đạt được mục tiêu của mình. bạn cần cung cấp tiêu điểm trong trường nhập của mình. Và trong khi viết các dẫn xuất ng-show của bạn, bạn cũng phải viết một logic không bằng. Giống như mã dưới đây:

<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

Chúng ta có thể sử dụng chức năng onfocus và onblur. Sẽ đơn giản và tốt nhất.

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

Thử ở đây:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.