Kullanıcı bir alandan ayrıldıktan sonra alanları doğrulayın


93

AngularJS ile, ng-pristineveya ng-dirtykullanıcının alana girip girmediğini tespit etmek için kullanabilirim . Ancak, istemci tarafı doğrulamasını yalnızca kullanıcı alan alanını terk ettikten sonra yapmak istiyorum. Bunun nedeni, bir kullanıcı e-posta veya telefon gibi bir alana girdiğinde, tam e-postasını yazmayı tamamlayana kadar her zaman bir hata mesajı alacak olmasıdır ve bu, optimum bir kullanıcı deneyimi değildir.

Misal


GÜNCELLEME:

Angular artık özel bir bulanıklaştırma etkinliğiyle birlikte geliyor: https://docs.angularjs.org/api/ng/directive/ngBlur


3
Sanırım bu, angularjs'in desteklemesi gereken bir şeydi ...
csg

Olabilir. Yerleşik form doğrulaması oldukça iyi çalışıyor, bunun yerleşik olmasını isteyip istemediğimi bilmiyorum. Sonuçta, çoğu kullanım durumu Angular'ın hemen doğrulamasını istiyorum. yani, bir sayı alanında, kullanıcı harfleri yazmaya başlarsa formun hemen geçersiz olmasını istiyorum.
mcranston18

11
bulanıklık doğrulaması 15 yıldan beri yaygındır ...
Olivvv

Yanıtlar:


75

Angular 1.3 artık ng model seçeneklerine sahip ve seçeneği { 'updateOn': 'blur'}örneğin olarak ayarlayabilir ve hatta kullanım çok hızlı yazarken veya birkaç pahalı DOM işleminden tasarruf etmek istediğinizde (bir model yazma birden fazla DOM yerine ve her tuş aşağıya doğru bir $ Digest döngüsünün olmasını istemezsiniz)

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

Varsayılan olarak, içerikte yapılan herhangi bir değişiklik bir model güncellemesini ve form doğrulamasını tetikleyecektir. Yalnızca belirtilen olaylar listesine bağlanmak için ngModelOptions direktifini kullanarak bu davranışı geçersiz kılabilirsiniz. Ie ng-model-options = "{updateOn: 'blur'}", yalnızca kontrol odağı kaybettikten sonra güncellenir ve doğrulanır. Alanla ayrılmış bir liste kullanarak birkaç olay ayarlayabilirsiniz. Ie ng-model-options = "{updateOn: 'mousedown blur'}"

Ve çürütmek

Geri çevrilme anahtarını ngModelOptions yönergesi ile kullanarak model güncellemesini / doğrulamasını geciktirebilirsiniz. Bu gecikme, ayrıştırıcılar, doğrulayıcılar ve $ dirty veya $ pristine gibi model bayrakları için de geçerli olacaktır.

Ie ng-model-options = "{debounce: 500}", model güncellemesini ve form doğrulamasını tetiklemeden önce son içerik değişikliğinden bu yana yarım saniye bekleyecektir.


2
Çoğu durumda bu, sorunu çözmez, çünkü muhtemelen ng-changekullanıcı alandan ayrılmadan önce olayları almak isteyebilirsiniz . Örneğin, benim durumumda, giriş alanı geçerli olur olmaz API'mden yeni veri talep ediyorum, ancak geçersiz olduğu anda bir hata mesajı göstermek istemiyorum - bunu yalnızca geçerli olduğunda yapmak istiyorum geçersiz ve bulanıklık olayı meydana geldi.
Tom

@Tom Test ediyorum 1.3.0 rc-3ve şu ana changekadar ateşlenmiyor blur, şunu kontrol edin: plnkr.co/edit/RivVU3r7xfHO1hUybqMu?p=preview
Gill Bates

Bu gerçekten kabul edilmiş, en iyi cevap olmalıdır. Tek bir mülk ekleyebileceğiniz zaman neden bir yönerge eklemelisiniz?
Dan Hulton

92

1.3.0 sürümünden itibaren bu $touched, kullanıcı sahayı terk ettikten sonra kolaylıkla yapılabilir .

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

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


1
Bu, her anahtarlamadan sonra doğrulamayı yine de yürütmez mi? OP, yalnızca kullanıcı sahayı terk ettikten sonra doğrulama yapmak istediğini belirtti.
comecme

@comecme evet olur, varsayılan ng-model-seçenekleri, updateOn: 'default'girişler, tuş yukarı ve
seçimler

5
Yine de buradaki büyük kusur, sahaya geri dönerseniz aynı doğrulama deneyimine sahip olmayacağınızdır. Zaten dokunulmaya ayarlı olduğundan, her tuş vuruşunda doğrulandığı ilk kareye döndünüz. Bunun bu kadar çok olumlu oy almasına şaşırdım.
dudewad

3
@dudewad bu doğru, ancak bunun UX açısından istenen davranış olduğunu düşünüyorum - geçersiz bir alana geri gelirseniz, hata mesajı siz ilk harfi yazana kadar değil, değer geçerli olana kadar devam etmelidir.
danbars

@dudewad Kullanıcının, bir alanı ilk doldurduktan sonra geçersiz olduğunu zaten bildikten sonra her basında doğrulamasına yardımcı olmaz mıydı? Alanın geçersiz olduğunu anladıklarında, alanın ne zaman geçerli olduğunu hızlı bir şekilde bilmek isteyeceklerdir ve her tuşa basıldığında doğrulama işlemi bu süreci hızlandırabilir mi?
Alan Dunning

32

@Jlmcdonald'ın önerdiği şeyi genişleterek bunu çözdüm. Tüm girdi ve seçme öğelerine otomatik olarak uygulanacak bir yönerge oluşturdum:

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

Bu , kullanıcı öğelere odaklandıkça / ziyaret ettikçe çeşitli öğelere ekleyecek has-focusve bunları has-visitedsınıflayacaktır. Ardından, doğrulama hatalarını göstermek için bu sınıfları CSS kurallarınıza ekleyebilirsiniz:

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

Bu, öğelerin hala $ geçersiz özellikler vb. Alması durumunda iyi çalışır, ancak CSS, kullanıcıya daha iyi bir deneyim sağlamak için kullanılabilir.


2
Neden sadece 'ngModel' yerine '? NgModel' gerekli? NgModel'in orada olmasını gerektirdiğini anlıyorum, ama neden soru işareti?
Noremac

2
Fikir için teşekkürler. JQuery gerektirdiğini belirtmelidir (sanırım - jql'de .closest () göremedim).
iandotkelly

1
Tüm <input> öğeleri ngModel tarafından desteklenmez (örneğin, giriş türü = gönderme). ? ngModel'i yalnızca onu destekleyen öğeler için gerektirir.
chmanie

5
Dürüst olmak gerekirse, gibi giriş alanı durumlarını ayarlamanın açısal yolundan sapmamalısınız formName.inputName.$dirty. formName.inputName.$focusedBulanıklaştırma için sınıf adlarını ve doğrulama için boole'ları kullanmak yerine, benzer bir mantıksal benzeri yazmak için yönergeyi düzenlemeyi öneririm .
Tom

17

Bunu oldukça basit bir CSS ile yapmayı başardım. Bu, hata mesajlarının ilişkili oldukları girdinin kardeşleri olmasını ve bir sınıfına sahip olmalarını gerektirir error.

:focus ~ .error {
    display:none;
}

Bu iki gereksinimi karşıladıktan sonra, bu, odaklanmış bir girdi alanıyla ilgili herhangi bir hata mesajını gizleyecektir, bence angularjs yine de yapması gereken bir şey. Gözden kaçmış gibi görünüyor.


2
Ahh. Bu, gitmenin akıllıca bir yoludur. Bunu yapmak için javascript yazmak yerine bunu tercih ederim.
güverte

5
Bu yaklaşımın dezavantajı, birisi bir hatayı düzeltirken hatanın artık görünür olmamasıdır ki bu ideal değildir. İdeal olan, hatanın bulanıklaşana kadar görünmemesi, ancak düzeltilene kadar kaybolmamasıdır.
Chris Nicola

4

Bu, yeni açısal sürümlerde standart olarak uygulanmış gibi görünüyor.

Sınıflar ng-bakir ve dokunduğu ng önce sırasıyla ayarlanır ve kullanıcı sonra doğrulanmış öğe odağı olmuştur.

CSS

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

4

İlgili lambinator en @ çözümü ... Ben angularjs 1.2.4 aşağıdaki hatayı başlamıştı:

Hata: [$ rootScope: inprog] $ özet zaten devam ediyor

Yanlış bir şey mi yaptığımdan yoksa bunun Angular'da bir değişiklik olup olmadığından emin değilim, ancak scope.$applyifadeleri kaldırmak sorunu çözdü ve sınıflar / durumlar hala güncelleniyor.

Bu hatayı da görüyorsanız, şunu deneyin:

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 () yöntemini saran (ve tetiklendiğinde bir doğrulama işlevi çalıştıran) özel bir yönerge yazmanız işe yarayabilir; örnek bir olan Angular sorunu var (ayrıca Angular tarafından yerel olarak desteklenmeyen diğer olaylara bağlanabilen genel bir direktif):

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

Bu rotaya gitmek istemiyorsanız, diğer seçeneğiniz sahada $ watch'u kurmak ve alan doldurulduğunda tekrar doğrulamayı tetiklemek olacaktır.


2

Verilen yanıtları daha fazla anlamak için, CSS3 sözde sınıflarını kullanarak ve yalnızca kullanıcı alana odaklanmayana kadar doğrulama hatalarının görüntülenmesini geciktirmek için ziyaret edilen alanları bir sınıfla işaretleyerek giriş etiketlemeyi basitleştirebilirsiniz:

(Örnek, jQuery gerektirir)

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

@nicolas cevabına dayanmaktadır .. Saf CSS hile, hata mesajını yalnızca bulanıklıkta gösterecektir

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

Bu iyidir, ancak kullanıcı alanda tekrar tıkladığında hata mesajı kaybolur ki bu ideal değildir.
Bennett McElwee

2

Burada ng mesajları (açısal 1.3'te mevcuttur) ve özel bir direktif kullanan bir örnek verilmiştir.

Doğrulama mesajı, kullanıcı giriş alanından ilk kez çıktığında bulanık olarak görüntülenir, ancak değeri düzelttiğinde, doğrulama mesajı hemen kaldırılır (artık bulanıklaşmaz).

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. Modülünüze ngMessages'ı indirmeyi ve eklemeyi unutmayın:

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

1

AngularJS 1.3'teki ng-model-seçeneklerinin (bu yazı itibariyle beta) {updateOn: 'blur'} 'u desteklediği belgelenmiştir. Önceki sürümler için, aşağıdaki gibi bir şey benim için çalıştı:

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

Bunun gibi bir şablonla:

<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

Alan durumunu kullanın $ touched Aşağıdaki örnekte gösterildiği gibi bunun için alana dokunulmuştur.

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

0

Has-error css sınıfını (bootstrap kullandığınızı varsayarak) ng-sınıfını ve ilişkili denetleyicinin kapsamındaki bir özelliği kullanarak dinamik olarak ayarlayabilirsiniz:

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>

Denetleyici:

$scope.badEmailAddress = false;

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

0

Bootstrap 3 ve lesscss kullanıyorsanız, aşağıdaki daha az kod parçacığı ile bulanıklık doğrulamasını etkinleştirebilirsiniz:

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

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

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

0

bir yönerge kullandım. İşte 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');
            });
        }
    }
})

Tüm girdi denetimim, sonraki öğe olarak bir span öğesine sahiptir; bu, doğrulama mesajımın görüntülendiği yerdir ve bu nedenle, bir öznitelik olarak yönerge her girdi denetimine eklenir.

Yönergede başvurulduğunu gördüğünüz css dosyamda (isteğe bağlı) .has-focus ve has-visit css sınıfım var.

NOT: 'on-blur-val'i giriş kontrolünüze kesme işareti olmadan tam olarak bu şekilde eklemeyi unutmayın.


0

Ng-odak kullanarak hedefinize ulaşabilirsiniz. girdi alanınızda ng odağı sağlamanız gerekir. Ve ng-show türevlerinizi yazarken, eşit olmayan bir mantık da yazmalısınız. Aşağıdaki kod gibi:

<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 ve onblur fonksiyonlarını kullanabiliriz. Basit ve en iyisi olur.

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

Burada deneyin:

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.