55

例から取得した保存ボタンを含むAngularアプリがあります:

<button ng-click="save" ng-disabled="form.$invalid">SAVE</button>

これは、ユーザーが問題を修正すると false になるため、クライアント側の検証には最適ですform.$invalidが、別のユーザーが同じ電子メールで登録されている場合、無効に設定されている電子メール フィールドがあります。

電子メール フィールドを無効に設定するとすぐに、フォームを送信できなくなり、ユーザーはその検証エラーを修正する方法がありません。form.$invalidそのため、送信ボタンを無効にするために使用できなくなりました。

もっと良い方法があるに違いない

4

5 に答える 5

75

これは、カスタム ディレクティブが役立つ別のケースです。ディレクティブを作成し、そこに $http または $resource を挿入して、検証中にサーバーにコールバックすることをお勧めします。

カスタム ディレクティブの擬似コード:

app.directive('uniqueEmail', function($http) {
  var toId;
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function(scope, elem, attr, ctrl) { 
      //when the scope changes, check the email.
      scope.$watch(attr.ngModel, function(value) {
        // if there was a previous attempt, stop it.
        if(toId) clearTimeout(toId);

        // start a new attempt with a delay to keep it from
        // getting too "chatty".
        toId = setTimeout(function(){
          // call to some API that returns { isValid: true } or { isValid: false }
          $http.get('/Is/My/EmailValid?email=' + value).success(function(data) {

              //set the validity of the field
              ctrl.$setValidity('uniqueEmail', data.isValid);
          });
        }, 200);
      })
    }
  }
});

そして、マークアップでそれを使用する方法は次のとおりです。

<input type="email" ng-model="userEmail" name="userEmail" required unique-email/>
<span ng-show="myFormName.userEmail.$error.uniqueEmail">Email is not unique.</span>

編集: 上記で何が起こっているかについての簡単な説明。

  1. 入力の値を更新すると、$scope.userEmail が更新されます
  2. ディレクティブには、リンク関数で設定された $scope.userEmail の $watch があります。
    • $watch がトリガーされると、$http ajax 呼び出しを介してサーバーに呼び出しを行い、電子メールを渡します
    • サーバーは電子メール アドレスをチェックし、「{ isValid: true }」のような単純な応答を返します。
    • その応答は、コントロールの $setValidity に使用されます。
  3. uniqueEmail の有効性状態が false の場合にのみ表示するように設定された ng-show を含むマークアップがあります。

... ユーザーにとっては、次のことを意味します。

  1. 電子メールを入力します。
  2. わずかな一時停止。
  3. メールが一意でない場合、「メールは一意ではありません」というメッセージに「リアルタイム」と表示されます。

EDIT2: これにより、 form.$invalid を使用して送信ボタンを無効にすることもできます。

于 2012-10-12T18:57:11.087 に答える
30

いくつかのプロジェクトでこれが必要だったので、ディレクティブを作成しました。最後に、ドロップイン ソリューションが必要な人のために、GitHub にアップするのに時間がかかりました。

https://github.com/webadvanced/ng-remote-validate

特徴:

  • テキストまたはパスワード入力の Ajax 検証のためのドロップイン ソリューション

  • Angulars ビルドの検証で動作し、formName.inputName.$error.ngRemoteValidate でアクセスできます。

  • サーバー要求を抑制し (デフォルトは 400 ミリ秒)、次のように設定できます。ng-remote-throttle="550"

  • HTTP メソッド定義 (デフォルトの POST) を許可しますng-remote-method="GET"

ユーザーが現在のパスワードと新しいパスワードを入力する必要があるパスワード変更フォームの使用例:

<h3>Change password</h3>
<form name="changePasswordForm">
    <label for="currentPassword">Current</label>
    <input type="password" 
           name="currentPassword" 
           placeholder="Current password" 
           ng-model="password.current" 
           ng-remote-validate="/customer/validpassword" 
           required>
    <span ng-show="changePasswordForm.currentPassword.$error.required && changePasswordForm.confirmPassword.$dirty">
        Required
    </span>
    <span ng-show="changePasswordForm.currentPassword.$error.ngRemoteValidate">
        Incorrect current password. Please enter your current account password.
    </span>

    <label for="newPassword">New</label>
    <input type="password"
           name="newPassword"
           placeholder="New password"
           ng-model="password.new"
           required>

    <label for="confirmPassword">Confirm</label>
    <input ng-disabled=""
           type="password"
           name="confirmPassword"
           placeholder="Confirm password"
           ng-model="password.confirm"
           ng-match="password.new"
           required>
    <span ng-show="changePasswordForm.confirmPassword.$error.match">
        New and confirm do not match
    </span>

    <div>
        <button type="submit" 
                ng-disabled="changePasswordForm.$invalid" 
                ng-click="changePassword(password.new, changePasswordForm);reset();">
            Change password
        </button>
    </div>
</form>
于 2014-04-09T18:35:59.307 に答える
17

私にぴったりのソリューションでプランカーを作成しました。カスタム ディレクティブを使用しますが、単一のフィールドではなくフォーム全体で使用します。

http://plnkr.co/edit/HnF90JOYaz47r8zaH5JY

サーバー検証のために送信ボタンを無効にすることはお勧めしません。

于 2013-01-07T06:17:47.530 に答える
5

Ok。作業バージョンが必要な場合は、ここにあります。

ドキュメントから:

 $apply() is used to enter Angular execution context from JavaScript

 (Keep in mind that in most places (controllers, services) 
 $apply has already been called for you by the directive which is handling the event.)

これは私たちが必要ないと思いました: $scope.$apply(function(s) {そうでなければそれは文句を言うでしょう$digest

app.directive('uniqueName', function($http) {
    var toId;
    return {
        require: 'ngModel',
        link: function(scope, elem, attr, ctrl) {
            //when the scope changes, check the name.
            scope.$watch(attr.ngModel, function(value) {
                // if there was a previous attempt, stop it.
                if(toId) clearTimeout(toId);

                // start a new attempt with a delay to keep it from
                // getting too "chatty".
                toId = setTimeout(function(){
                    // call to some API that returns { isValid: true } or { isValid: false }
                    $http.get('/rest/isUerExist/' + value).success(function(data) {

                        //set the validity of the field
                        if (data == "true") {
                            ctrl.$setValidity('uniqueName', false);
                        } else if (data == "false") {
                            ctrl.$setValidity('uniqueName', true);
                        }
                    }).error(function(data, status, headers, config) {
                        console.log("something wrong")
                    });
                }, 200);
            })
        }
    }
});

HTML:

<div ng-controller="UniqueFormController">

        <form name="uniqueNameForm" novalidate ng-submit="submitForm()">

            <label name="name"></label>
            <input type="text" ng-model="name" name="name" unique-name>   <!-- 'unique-name' because of the name-convention -->

            <span ng-show="uniqueNameForm.name.$error.uniqueName">Name is not unique.</span>

            <input type="submit">
        </form>
    </div>

コントローラーは次のようになります。

app.controller("UniqueFormController", function($scope) {
    $scope.name = "Bob"
})
于 2013-10-22T14:35:49.150 に答える
3

https://github.com/webadvanced/ng-remote-validateについて学んだこのページからの回答のおかげで

オプション ディレクティブは、ディレクティブを記述する各フィールドとして、あまり好きではありません。モジュールは同じです - 普遍的なソリューションです。

しかし、モジュールで何かが欠けていました - フィールドでいくつかのルールを確認してください。
次に、モジュールhttps://github.com/borodatych/ngRemoteValidate
ロシアの README の謝罪を変更しましたが、最終的には変更されます。
同じ問題を抱えている人が突然いることを共有することを急いでいます。
はい、そして私たちはこのためにここに集まりました...

ロード:

<script type="text/javascript" src="../your/path/remoteValidate.js"></script>

含む:

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

HTML

<input type="text" name="login" 
ng-model="user.login" 
remote-validate="( '/ajax/validation/login', ['not_empty',['min_length',2],['max_length',32],'domain','unique'] )" 
required
/>
<br/>
<div class="form-input-valid" ng-show="form.login.$pristine || (form.login.$dirty && rv.login.$valid)">
    From 2 to 16 characters (numbers, letters and hyphens)
</div>
<span class="form-input-valid error" ng-show="form.login.$error.remoteValidate">
    <span ng:bind="form.login.$message"></span>
</span>

バックエンド [コハナ]

public function action_validation(){

    $field = $this->request->param('field');
    $value = Arr::get($_POST,'value');
    $rules = Arr::get($_POST,'rules',[]);

    $aValid[$field] = $value;
    $validation = Validation::factory($aValid);
    foreach( $rules AS $rule ){
        if( in_array($rule,['unique']) ){
            /// Clients - Users Models
            $validation = $validation->rule($field,$rule,[':field',':value','Clients']);
        }
        elseif( is_array($rule) ){ /// min_length, max_length
            $validation = $validation->rule($field,$rule[0],[':value',$rule[1]]);
        }
        else{
            $validation = $validation->rule($field,$rule);
        }
    }

    $c = false;
    try{
        $c = $validation->check();
    }
    catch( Exception $e ){
        $err = $e->getMessage();
        Response::jEcho($err);
    }

    if( $c ){
        $response = [
            'isValid' => TRUE,
            'message' => 'GOOD'
        ];
    }
    else{
        $e = $validation->errors('validation');
        $response = [
            'isValid' => FALSE,
            'message' => $e[$field]
        ];
    }
    Response::jEcho($response);
}
于 2015-07-20T12:14:35.283 に答える