Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/377.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何防止$setViewValue触发$watch_Javascript_Jquery_Angularjs - Fatal编程技术网

Javascript 如何防止$setViewValue触发$watch

Javascript 如何防止$setViewValue触发$watch,javascript,jquery,angularjs,Javascript,Jquery,Angularjs,我已经指示wrapps是一个jQuery插件: angular.module('ngJQueryPlugin', []) .controller('MainCtrl', function ($scope) { $scope.input = {'hexa': 0}; }) .directive('jQueryPlugin', function ($compile, $parse) { return { restrict: 'E', r

我已经指示wrapps是一个jQuery插件:

angular.module('ngJQueryPlugin', [])
  .controller('MainCtrl', function ($scope) {
    $scope.input = {'hexa': 0};
  })
  .directive('jQueryPlugin', function ($compile, $parse) {
      return {
        restrict: 'E',
        require: '?ngModel',
        link: function ($scope, $element, $attributes, ngModel) {
          if (ngModel === null) return;
          $scope.$watch($attributes.ngModel, function (hexaFromModel) {
            $element.data('jQueryPlugin').updateJQueryPluginUI(hexaFromModel);
          }, true);
          $element.jQueryPluginConstructor({}, function (hexaFromjQueryPlugin) {
            $scope.$apply(function () {
              ngModel.$setViewValue({ hexa: hexaFromjQueryPlugin});
              ngModel.$render();
            });
          });
        }
      };
    });
指令实例化:

<jquery-plugin ng-model="input" />
<input type="text" ng-model="input.hexa"/>
指令中的scope watch跟踪每个模型更新并通知jQueryPlugin

jQueryPlugin构造函数中的第二个参数是回调函数,每次jQueryPlugin UI更新十六进制颜色时都会调用该函数。然后在作用域上设置新值

我的问题是$setViewValue导致调用$watch$查看jQueryPlugin的更新,这是无用的,因为我们最初从jQueryPlugin回调得到通知

我想到的一个解决方案是在作用域上使用标志来知道更新最初是在jQueryPlugin中启动的还是在作用域中启动的。这将阻止递归调用

还有别的办法吗?例如,即使模型已更新,也阻止$setViewValue触发$watch

更新: 我刚刚创造了一个plunker。
如果我在Angular的第一个输入中输入文本,jQuery插件将收到通知:正常行为。 如果我在来自jQuery组件的第二个输入中输入文本,则不应返回通知

      $scope.$watch($attributes.ngModel, function (hexaFromModel, oldValue) {
        if (hexaFromModel === oldValue) {
          return;
        }

        $element.data('jQueryPlugin').updateJQueryPluginUI(hexaFromModel);
      });

请注意,这不会停止调用手表,但如果没有更改,则会停止运行手表逻辑。

检测更改是否来自ngModel的一种方法。$setViewValue是与ngModel。$modelValue进行比较。你可以这样做:

$scope.$watch($attributes.ngModel, function (hexaFromModel) {
  if (angular.equals(hexaFromModel, ngModel.$modelValue)) {
    return;
  }

  $element.data('jQueryPlugin').updateJQueryPluginUI(hexaFromModel);
}, true);
ngModel.$formatters.push(function (value) {
  $element.data('jQueryPlugin').updateJQueryPluginUI(value);
});
或者,您也可以使用$formatters,而不是像这样查看$attributes.ngModel:

$scope.$watch($attributes.ngModel, function (hexaFromModel) {
  if (angular.equals(hexaFromModel, ngModel.$modelValue)) {
    return;
  }

  $element.data('jQueryPlugin').updateJQueryPluginUI(hexaFromModel);
}, true);
ngModel.$formatters.push(function (value) {
  $element.data('jQueryPlugin').updateJQueryPluginUI(value);
});
希望这有帮助

编辑:事实证明hexaFromModel实际上是一个对象,而不是一个简单的字符串,这使得上述解决方案毫无用处

在这种情况下,如果更新来自插件,我想不出比设置一个标志绕过watch侦听器更好的解决方案了。像这样:

var updatingByPlugin = false;

$scope.$watch($attributes.ngModel, function(newValue, oldValue) {
  if (updatingByPlugin) {
    return;
  }

  jQueryPlugin.update(newValue);
}, true);

jQueryPlugin = new jQueryPluginConstructor($element, {}, function(hexFromjQueryPlugin) {
  console.log('notified');

  updatingByPlugin = true;

  $scope.$apply(function () {
    ngModel.$setViewValue({
      hex: hexFromjQueryPlugin
    });
  });

  updatingByPlugin = false;
});

示例plunker:

您应该编写$render函数,而不是调用它:

angular.module('ngJQueryPlugin', [])
  .controller('MainCtrl', function ($scope) {
    $scope.input = {'hexa': 0};
  })
  .directive('jQueryPlugin', function ($compile, $parse) {
      return {
        restrict: 'E',
        require: '?ngModel',
        link: function ($scope, $element, $attributes, ngModel) {
          if (ngModel === null) return;
          ngModel.$render = function () {
                 if(ngModel.$viewValue)
                     $element.data('jQueryPlugin').updateJQueryPluginUI(ngModel.$viewValue);
          }
          $element.jQueryPluginConstructor({}, function (hexaFromjQueryPlugin) {
            $scope.$apply(function () {
              ngModel.$setViewValue({ hexa: hexaFromjQueryPlugin});
            });
          });
        }
      };
    });

看来您不需要双向绑定。那你为什么要用ng模型呢?我确实想要一个双向绑定。这就是我的目标。问题在于:jQueryPlugin更新=>回调=>$setViewValue=>$watch。我不知道$watch将被调用,在这种情况下,$setViewValue已经执行了绑定。但是我需要在这个场景中调用它:Scope model update=>watch=>jQueryPlugin update;不修改范围。你会如何直接设置它?我现在明白你的意思了,请看下面的答案。如果我们使用angular.equals来比较对象相等,而不是通过$scope来比较引用相等,那么这是不起作用的。$watch$attributes.ngModel,函数hexaFromModel{if hexaFromModel==oldValue//always false},true;请参阅初始问题的更新。我已经创建了一个plunkr。如果我在Angular的第一个输入中输入文本,jQuery插件将收到通知:正常行为。如果我在jQuery组件的第二个输入中输入文本,则不应返回通知。请看我编辑的答案。非常感谢runTarm的帮助和帮助。实际上,我已经想到了第一个问题中描述的标志解决方案。我希望angularJs提供一些内部机制,防止$setViewValue回调$watch