【问题标题】:Avoid setTimeout to overlap the function on angular $watch避免 setTimeout 与角度 $watch 上的功能重叠
【发布时间】:2014-03-17 07:04:00
【问题描述】:

我有两个 div 淡入或淡出的验证过程,具体取决于第一个函数的返回。 setTimeout 是让完成输入输入,因为它会监视 keyup。系统工作,但问题发生在以下情况:

您输入了错误的值(#wrong 出现)> 您重新输入了正确的值 > 当您输入正确的值时,else 函数被触发,因为它尚未完成 > 当输入正确的值时 (. ok 出现)#wrong 也出现,在 setTimeout 延迟之后。

有没有办法避免 else 函数的重叠?也许将真假功能完全分开?

function validatePasscode(code) {
    if (array.indexOf(code) > -1) {
        return true;
    }  
}

$scope.$watch('passcode', function(value) {
    var isValid = validatePasscode(value);
    if (isValid) { 
        $scope.loadNewChannel(); 
        $('.ok').fadeIn(200); 
        $('#wrong').fadeOut(200);
    }
    else {
        setTimeout(function(){
            $('.ok').fadeOut(200); 
            $('#wrong').delay(200).fadeIn(200);
        },2000);
    }
});

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    请始终调用 clearTimeout()

    var timeoutFunction;
    $scope.$watch('passcode', function(value) {
    var isValid = validatePasscode(value);
    clearTimeout(timeoutFunction);
    if (isValid) { 
        $scope.loadNewChannel(); 
        $('.ok').fadeIn(200); 
        $('#wrong').fadeOut(200);
    }
    else {
        setTimeout(function(){
            $('.ok').fadeOut(200); 
            $('#wrong').delay(200).fadeIn(200);
        },2000);
    }
    

    });

    【讨论】:

    • 谢谢,逻辑看起来不错,但问题仍然存在。我应该使用 $timeout 而不是 setTimeout 吗?
    • 你绝对应该在 angular 中使用 $timeout 而不是 setTimeout
    【解决方案2】:

    我会采取一些不同的方法。 Angular 的想法不是在控制器内部进行 DOM 操作。您有几个选择 - 一个是在 $scope 上公开 $isValid,另一个是创建一个执行动画的指令。

    至于限制输入,问题是您在每次按键后任意等待2秒。您真正想要的是等到按键完成 - 即只要有人在输入等待,然后在他们暂停一段时间后重新评估。

    您可以使用 Underscore 或 Lo-dash 的 debounce 来做到这一点。像这样的:

    var applyValidation = function($scope) {
       $scope.isValid = validatePasscode($scope.passcode);
    }
    

    因为 debounce 在 Angular 的摘要循环之外触发,你需要 $apply 它:

    var validationDelayed = function($scope) {
        $scope.$apply(function(){applyValidation($scope);});
    };
    

    然后您可以观看它,并且只有在输入稳定后才会做出反应。这只会在用户停止输入 1 秒后触发检查:

    var validationThrottled = _.debounce(validationDelayed, 1000);
    $scope.$watch('passcode', function(){validationThrottled($scope);});
    

    同样,这将解决超时问题,但我强烈建议将其移动到动画指令中,尽管您当然可以在此代码中尝试如下:

    var applyValidation = function($scope) {
       if(validatePasscode($scope.passcode)) {
          // success animation
       } 
       else {
          // failure animation
       }
    }
    

    这是我的一个使用类似概念的工作小提琴:http://jsfiddle.net/jeremylikness/5KeMw/(我正在过滤而不是验证,但你可以看到油门是如何工作的)和一篇关于它的博客文章:http://csharperimage.jeremylikness.com/2013/10/throttling-input-in-angularjs.html

    【讨论】:

    • 谢谢,它有效。现在唯一的问题是,将开头的空输入字段视为失败(从而显示失败 div)。是否可以仅在开始输入后才应用验证功能?现在我会用这个,我正在学习,我会看看如何暴露$isValid。
    • 不用担心 - 你可以做两件事之一。如果您想忽略空,只需使用 _.isEmpty() 来检查并仅验证它是否为空(即他们开始输入)。如果您想在初始之后检查是否为空,那么您可以在第一次不为空时设置一个标志并以这种方式进行检查。如果您在表单中绑定 HTML,则有更多选项,例如查看 $pristine 和 $dirty。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-20
    • 1970-01-01
    • 2022-01-04
    • 2018-02-12
    • 2020-08-07
    相关资源
    最近更新 更多