【问题标题】:Angularjs - Checking duplicated email on blur in directiveAngularjs - 检查指令中模糊的重复电子邮件
【发布时间】:2014-11-01 16:41:32
【问题描述】:

当我想检查邮件是否已在数据库中注册时遇到了问题,但仅限于 blur 事件(我不希望它检查每个更改)。所以我写了一个指令,我可以在我的应用程序的其他地方重复使用。但问题是即使我仍然没有模糊,指令也会继续检查,这是我的 plnkr 供参考:http://plnkr.co/edit/eUPFxIc78Wkl4mCX6hrk?p=preview

这是我的指令代码:

app.directive('checkEmail', function(userService){
return{
    restrict: "A",
    require:'ngModel',
    link: function( scope, ele, attrs, ctrl ){

        ele.bind('blur', function(){
            console.log("Run in blur!");

            ctrl.$parsers.unshift(function( email ){
                console.log("Email is ", email);

                // Checking to see if the email has been already registered
                if( ele.val() && userService.isDuplicateEmail(email) ){
                    ctrl.$setValidity('isDuplicatedEmail', true );                        
                }else{
                    ctrl.$setValidity('isDuplicatedEmail', false );
                }
            });

        })
    }
}

})

抱歉,我是 Angular 新手,这个简单的任务已经让我发疯了。请看一下我的指令并告诉我我能做些什么来解决这个问题。提前致谢

【问题讨论】:

    标签: angularjs unique blur directive


    【解决方案1】:

    如果您只需要在模糊时检查电子邮件,那么您不需要将其传递到ng-model$parsers 数组中。模糊时只需更改有效性即可。

    DEMO

    类似这样的:

       ele.bind('blur', function(){
          ctrl.$setValidity('isDuplicatedEmail', ctrl.$viewValue && userService.isDuplicateEmail(ctrl.$modelValue));
          scope.$digest();
       });
    

    或者,如果您从服务器异步检查电子邮件,那么这可能对您不利。下面的例子是一个更好的答案:

    DEMO

    下面的服务,请求来自服务器的电子邮件列表并解决电子邮件是否存在(真)或不存在(假)的承诺。

    app.service('userServiceAsync', function($http, $q) {
    
      this.isDuplicateEmailAsync = function(email) {
        var deferred = $q.defer(), i;
    
        $http.get('users.json')
          .success(function(users) {
            for(i = 0; i < users.length; i++) {
              if(users[i].email == email) {
                deferred.resolve(true);
                return;
              }
            }
            deferred.resolve(false);
          })
    
          .error(function() {
            deferred.resolve(false);
          });
    
        return deferred.promise;
      };
    
    });
    

    下面的指令将isDuplicatedEmail 有效性键设置为真或假,具体取决于userServiceAsync.isDuplicateEmailAsync () 方法的解析值。作为奖励,我在ngModelController 的对象中添加了一个行列式键来检查异步请求是否仍在进行中(使用__CHECKING_EMAIL 键)。

    app.directive('checkEmailAsync', function(userServiceAsync) {
      return {
        require: 'ngModel',
        link: function(scope, elem, attrs, ctrl) {
          elem.bind('blur', function() {
            ctrl.__CHECKING_EMAIL = true;
            userServiceAsync.isDuplicateEmailAsync(ctrl.$viewValue).then(function(hasEmail) {
              ctrl.$setValidity('isDuplicatedEmail', !hasEmail);
            })['finally'](function() {
              ctrl.__CHECKING_EMAIL = false;
            });
          });
        }
      }
    });
    

    HTML

      Check Email Asynchronously
      <input type="text" name="emailAsync" placeholder="Email" ng-model="emailAsync" check-email-async required />
      <div ng-show="registerForm.emailAsync.__CHECKING_EMAIL">
        Checking Email...
      </div>
    

    【讨论】:

    • 感谢您的支持,实际上我需要在我的真实应用程序中进行异步调用,如您所说。但我还有一些其他问题要从你的回答中问 1) 我什么时候应该使用 $parsers,我已经阅读了一些关于自定义验证的教程,他们使用的只是 $parsers$formatters 的东西,2) 检查你的异步示例,由于错误输出仍未显示,我已将输出更改为 &lt;span style="color:red" ng-show="registerForm.emailAsync.$error.isDuplicateEmail"&gt;Email already used&lt;/span&gt; 并使用 scope.$apply() 进行 UI 更新,但没有任何变化。任何想法为什么?
    • $parsers 用于将文本从视图(输入值)格式化为模型($scope 值)。至于异步的问题,我已经修复了,使用isDuplicatedEmail,再次查看第二个DEMO。
    • 谢谢,但你能再看看第二个演示链接吗?似乎它仍然是旧版本,并且在重复电子邮件时仍然没有显示错误输出。谢谢。我像这样改变了一点,它可以工作,ctrl.$setValidity('isDuplicatedEmail', **!hasEmail**);
    • 我已经编辑过了,和你现在评论里提到的一样。
    【解决方案2】:

    @ryeballar ,对不起,但这对我来说仍然不合适。我已经修改了您的 plnk,使其仅适用于异步。所以我的困惑是这条线 ctrl.$setValidity('isDuplicatedEmail', !hasEmail);,您可以访问新plnk here

    如果我之前没有输入“”,那个布尔值似乎不正确,你可以在控制台日志中检查它并查看它的值,就像电子邮件没有重复一样,服务返回false,然后我们将有效性设置为"TRUE",以使其看起来像"RIGHT"

    指令如下:

    elem.bind('blur', function() {
        ctrl.__CHECKING_EMAIL = true;
        userServiceAsync.isDuplicateEmailAsync(ctrl.$viewValue).then(function(hasEmail) {
            console.log("hasEmail: ", hasEmail);
            console.log("!hasEmail: ", !hasEmail);
    
            scope.hasEmail = hasEmail;
            // HERE IS THE CONFUSION, WHY !hasEmail works correctly ????
            // THIS WILL GIVE THE WRONG ANSWER
            // ctrl.$setValidity('isDuplicatedEmail', hasEmail);
    
            // THIS WILL GIVE THE RIGHT ANSWER
            ctrl.$setValidity('isDuplicatedEmail', !hasEmail);
    
    
        })['finally'](function() {
          ctrl.__CHECKING_EMAIL = false;
        });
      });
    

    【讨论】:

      【解决方案3】:

      请在此处查看工作示例http://plnkr.co/edit/lT9kO4nU0OeBG3g8lULG?p=preview

      请不要忘记添加范围。$apply 以更新您的 UI

      app.directive('checkEmail', function(userService) {
        return {
          restrict: "A",
          require: 'ngModel',
          link: function(scope, ele, attrs, ctrl) {
      
            ele.bind('blur', function() {
              scope.$apply(function() {
                console.log("Run in blur!");
                // Checking to see if the email has been already registered
                if (userService.isDuplicateEmail(scope.email)) {
      
                  ctrl.$setValidity('isDuplicatedEmail', false);
      
      
                  return scope.email;;
                } else {
      
                  ctrl.$setValidity('isDuplicatedEmail', true);
      
                  return scope.email;
                }
              });
      
      
            })
          }
        }
      })
      

      【讨论】:

      • 感谢您提供的具体细节,它就像一个魅力。但是你能解释一下为什么当你把代码放在 scope.$apply 里面并且它可以工作吗?在我发布这个问题之前,我尝试过与您的解决方案类似的方法,我将 setValidity 代码放在开头,然后是 scope.$apply();到底。我以为它会再运行一次 $digest 循环来更新 UI,但当时我错了。你能帮我澄清一下吗?
      • @DucHong 您更有可能以两种方式做到这一点。我这样做只是为了让代码更干净。
      • 其实在这种情况下我不能调用作用域。最后$apply,我认为它与作用域有关,这里是你代码的修改版本,http://plnkr.co/edit/lgDiHvqtvhY1dROUWLDF?p=preview跨度>
      • @DucHong your scope.$apply 在'return'之后,所以从未调用过,请看这里plnkr.co/edit/8IjT5En1TN7w0lNpTUNa?p=preview
      【解决方案4】:

      $parser.unshift 在模型更改时执行,但您确实想要“模糊”,...检查 ngModelOptions 的“updateOn”或删除 unshift...

      您也可以使用 ctrl.$viewValue。

              ele.bind('blur', function(){
                  console.log("Run in blur!");
      
                  //ctrl.$parsers.unshift(function( email ){
                      email = ctrl.$viewValue;
                      console.log("Email is ", email);
      
                      // Checking to see if the email has been already registered
                      if( !!email && userService.isDuplicateEmail(email) ){
                          ctrl.$setValidity('isDuplicatedEmail', true );
      
                          return email;;
                      }else{
                          ctrl.$setValidity('isDuplicatedEmail', false );
      
                          return email;
                      }
      
                  //});
      
              })
      

      【讨论】:

      • 感谢您的评论,ngModelOptions 对我来说真的很陌生。但是你能更清楚地解释一下我们使用$parser$formatter 的方式吗?我已经阅读了一些关于指令自定义验证的教程,其中大多数在他们的自定义函数中使用这些。我以为我走在正确的道路上,但事实并非如此
      • 这可能会有所帮助...stackoverflow.com/questions/22841225/…
      猜你喜欢
      • 1970-01-01
      • 2017-06-15
      • 2013-09-06
      • 2011-12-02
      • 1970-01-01
      • 2015-08-18
      • 1970-01-01
      • 2018-09-09
      • 1970-01-01
      相关资源
      最近更新 更多