ユーザーがフィールドを離れた後にフィールドを検証する


92

AngularJSでは、ng-pristineまたはng-dirtyを使用して、ユーザーがフィールドに入力したかどうかを検出できます。ただし、クライアント側の検証は、ユーザーがフィールド領域を離れた後にのみ実行したいと思います。これは、ユーザーが電子メールや電話などのフィールドに入ると、完全な電子メールの入力が完了するまで常にエラーがスローされ、これは最適なユーザーエクスペリエンスではないためです。


更新:

Angularにはカスタムのぼかしイベントが付属しています:https : //docs.angularjs.org/api/ng/directive/ngBlur


3
これはangularjsがサポートすべきものだったと思います...
csg

多分。組み込みのフォーム検証は、これを組み込みたいかどうかわからないほどうまく機能します。結局のところ、ほとんどのユースケースでは、Angularがすぐに検証することを望んでいます。つまり、数値フィールドでは、ユーザーが文字を入力し始めたときにフォームをすぐに無効にしたいと考えています。
mcranston18 2014

11
ぼかしの検証は15年以来一般的です...
Olivvv 2014

回答:


75

Angular 1.3にng-model-optionsが追加され、オプションを次のように設定できます { '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'}"

そしてデバウンス

ngModelOptionsディレクティブでデバウンスキーを使用することで、モデルの更新/検証を遅らせることができます。この遅延は、パーサー、バリデーター、および$ dirtyや$ pristineなどのモデルフラグにも適用されます。

つまり、ng-model-options = "{debounce:500}"は、最後のコンテンツ変更から0.5秒待ってから、モデルの更新とフォームの検証をトリガーします。


2
ほとんどの場合ng-change、ユーザーがフィールドを離れる前にイベントを受信する必要があるため、これで問題が解決することはありません。たとえば、私の場合、入力フィールドが有効になるとすぐにAPIから新しいデータをリクエストしますが、無効になるとすぐにエラーメッセージを表示したくありません。無効で、ぼかしイベントが発生しました。
トム

@Tom私はテスト中で1.3.0 rc-3changeまで起動しません。blurこれを確認してください:plnkr.co/edit/RivVU3r7xfHO1hUybqMu?p
Gill Bates

これは本当に受け入れられるべきトップ回答です。単一のプロパティを追加できるのに、なぜディレクティブを追加するのですか?
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

@comecmeはい、そうです、デフォルトのng-model-optionsはupdateOn: 'default'、入力、キーアップ、および選択の場合、変更時を意味します
pocesar

5
ただし、ここでの大きな欠点は、現場に戻った場合、同じ検証経験が得られないことです。スクエア1に戻ります。すでにタッチされているため、すべてのキーストロークで検証されます。これが非常に多くの賛成票を獲得したことに驚いています。
dudewad

3
@dudewadは正しいですが、UXとしては望ましい振る舞いだと思います。無効なフィールドに戻った場合、最初の文字を入力するまでではなく、値が有効になるまでエラーメッセージが表示されます。
danbars 2016年

@dudewad最初にフィールドに入力した後、フィールドが無効であることをすでに知っているユーザーが、プレスごとに検証するのに役立ちませんか?フィールドが無効であることがわかったら、フィールドがいつ有効になるかをすぐに知りたいと思うでしょう。キーを押すたびに検証すると、そのプロセスが高速化されるでしょう。
アラン・ダニング

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
正直に言うと、のような入力フィールドの状態を設定する角度のある方法から逸脱してはなりませんformName.inputName.$dirty。ディレクティブを編集して、formName.inputName.$focusedblurにクラス名を使用し、検証にブール値を使用するのではなく、のような同様のブール値を作成することをお勧めします。
トム

17

私はこれをなんとかシンプルなCSSで実現できました。これには、エラーメッセージが関連する入力の兄弟であり、クラスがである必要がありerrorます。

:focus ~ .error {
    display:none;
}

これら2つの要件を満たした後、これにより、フォーカスされた入力フィールドに関連するエラーメッセージが非表示になります。見落としのようです。


2
ああ。これは賢い方法です。私はそれを行うためにJavaScriptを書くよりもこれを好みます。
デッキ

5
このアプローチの欠点は、誰かがエラーを修正しているときにエラーが見えなくなることです。これは理想的ではありません。理想は、エラーがぼやけるまで表示されず、修正されるまで消えないことです。
Chris Nicola、

4

これはangularの新しいバージョンで標準として実装されているようです。

ng-untouchedおよびng-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()メソッドをラップする(そしてトリガーされたときに検証関数を実行する)カスタムディレクティブを作成するとうまくいく場合があります。サンプル問題があるAngularの問題があります(Angularでネイティブにサポートされていない他のイベントにバインドできる一般的なディレクティブも同様です):

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

そのルートを使いたくない場合は、フィールドに$ watchを設定し、フィールドが入力されたときに検証をトリガーすることもできます。


2

与えられた回答をさらに詳しく調べるには、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>

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で利用可能)とカスタムディレクティブを使用した例です。

検証メッセージは、ユーザーが初めて入力フィールドを離れたときにぼかしに表示されますが、値を修正すると、検証メッセージはすぐに削除されます(ぼかしではなくなります)。

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

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

以下の例に示すように、フィールドの状態$ touchedを使用します。

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

0

ng-classと関連するコントローラーのスコープのプロパティを使用して、has-error cssクラス(ブートストラップを使用している場合)を動的に設定できます。

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

0

ブートストラップ3とlesscssを使用する場合、以下の少ないスニペットでぼかし検証を有効にできます。

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

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

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

0

ディレクティブを使用しました。これがコードです:

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要素があり、検証メッセージが表示されるため、属性としてのディレクティブが各入力コントロールに追加されます。

ディレクティブで参照されていることがわかるcssファイルに、(オプションの)has-focusおよびhas-visited cssクラスもあります。

注:「on-blur-val」をアポストロフィなしで入力コントロールにこの方法で正確に追加することを忘れないでください


0

使用することにより、NG-フォーカスを、あなたの目標を達成することができます。入力フィールドに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.