javascript - AngularJS : $watch vs. $observe when newValue === oldValue

标签 javascript angularjs angularjs-directive

如果这已经在某处解释或讨论过,我很抱歉,但我找不到任何地方讨论过这个确切的问题。

所以我有一个带有一个数据绑定(bind) 'myvar' 的 Angular Directive(指令)(= 或 @ 没有区别)。来自数据绑定(bind)的值在指令中使用:scope.myvarStr = scope.myvar + 'somestring'。然后我在模板中绑定(bind) myvarStr。

因为 scope.myvarStr 必须在 scope.myvar 更改时进行修改,所以我使用 $watch('myvar', function(...)) 来监视值并在需要时更新 scope.myVarStr。在 watch 函数中我放了经典的 if (newValue === oldValue) return;

问题在 $watch 第一次触发并且两个值相等时出现;然后 View 没有更新。我可以很容易地从链接函数第一行的 console.log(scope.myvar) 中看到 scope.myvar 是未定义的(或“依赖于绑定(bind)类型”),并且该值已更改为其他值我在 $watch 中做了一个 console.log。

我用谷歌搜索了一个小时左右,找到了这个:https://github.com/angular/angular.js/issues/11565 然而,这个问题没有在其他任何地方讨论过,所以我在谷歌上搜索了更多并遇到了 $observe AngularJS : Difference between the $observe and $watch methods

当我从 $watch 更改为 $observe 时,我所有的问题都消失了,我仍然可以使用 if(newValue === oldValue) return;。

(function(directives) {
'use strict';

directives.directive('someDir', [function() {
    return {
        restrict: 'E',
        scope: {
            myvar: '=' //or @ didn't matter at the time...
        },
        template: '<p>{{myvarStr}}</p>',
        link: function(scope, el, attrs) {

            function toString() {
                if (scope.myvar < 1000) {
                    scope.myvarStr = scope.myvar;
                } else {
                    scope.myvarStr = scope.myvar/1000 + 'k';
                }
            }
            toString();

            scope.$watch('myvar', function(newValue, oldValue) {
                console.log("changed", newValue, oldValue)
                if (newValue == oldValue) return;
                toString();
            },true);

            // When changing to $observe it works :)
            //attrs.$observe('myvar', function(newValue, oldValue) {
            //    console.log("changed", newValue, oldValue)
            //    if (newValue == oldValue) return;
            //    toString();
            //},true);

        }
    };
}]);
}(angular.module('myApp.directives')));

建议:据我所知,$watch 会出现此问题,因为范围值永远不会更改。指令需要一段时间才能获取值,直到那时绑定(bind)只是一个空字符串或其他东西,当检测到该值时 $watch 触发但实际范围值没有改变(或如第一个链接中所述; 当值“出现”在指令中时,第一个 watch 触发。

最佳答案

我不太明白你的建议/解释,但我觉得事情比你说的要简单得多。

您不需要 newValue === oldValue 测试,因为您的 watch-action 是幂等且廉价的。但即使你这样做,也只意味着你需要自己初始化值(例如,通过手动调用 toString()),你似乎正在这样做,因此你的指令应该按预期工作。 (事实上​​,我无法用您的代码重现您提到的问题。)

无论如何,这是一个(更简单的)working version :

.directive('test', function testDirective() {
  return {
    restrict: 'E',
    template: '<p>{{ strVal }}</p>',
    scope: {
      val: '='
    },
    link: function testPostLink(scope) {
      scope.$watch('val', function prettify(newVal) {
        scope.strVal = (!newVal || (newVal < 1000)) ?
            newVal : 
            (newVal / 1000) + 'K';
      });
    }
  };
})

顺便说一句,因为你只是想“格式化”一些显示值,所以看起来 filter$watch 更合适(并且清除 imo) >(参见 above demo):

.filter('prettyNum', prettyNumFilter)
.directive('test', testDirective)

function prettyNumFilter() {
  return function prettyNum(input) {
    return (!input || (input < 1000)) ? input : (input / 1000) + 'K';
  };
}

function testDirective() {
  return {
    template: '<p>{{ val | prettyNum }}</p>',
    scope: {val: '='}
  };
}

关于javascript - AngularJS : $watch vs. $observe when newValue === oldValue,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30356803/

相关文章:

javascript - Angular 服务未定义

javascript - 使用 HttpInterceptor 的 Angular 1.5 超时

javascript - 指令加载时间非常长,检查加载时间的方法

javascript - 切换汉堡下拉菜单 : How to call ancestor with JQuery?

javascript - Django + Vue.js 问题

javascript - Angularjs - 复选框 - 计算多个选定/未选定的项目

javascript - 具有更新内容的 AngularJS 固定列表

javascript - Angularjs - 动态模板 URL

javascript - 如何从 HTML 表单获取用户输入并将其存储在现有的 JavaScript 数组中

javascript - 匹配前面没有左括号的两个引号