AngularJS - 在更改模型值的指令,为什么我要叫$渲染? [英] AngularJS - In a directive that changes the model value, why do I have to call $render?

查看:133
本文介绍了AngularJS - 在更改模型值的指令,为什么我要叫$渲染?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我提出设计为附连到使用ngModel指令的元素的指令。如果模型的值相匹配的东西值应该再设置为previous值。在我的例子我在寻找富,并设置它回到previous如果这就是在键入

我的单元测试通过了这个很好,因为他们只在查看模型的价值。然而,在实践中,不更新在DOM当放回触发器。我们这里最好的猜测是,旧的设置==新的prevents的发生脏检查。我通过$ setViewValue方法踩,它似乎做什么它应该。然而,它不会设置新的值后更新DOM(和你在浏览器中看到的),直到我明确地调用ngModel。$渲染()。它工作正常,但我只是想看看是否有这样做的更合适的方式。

code是下面,这里是一个小提琴同用。

  angular.module('myDirective',[])
    .directive('myDirective',函数(){
    返回{
        限制:'A',
        终端:真实,
        要求:ngModel
        链接:功能(范围,元素,ATTRS,ngModel){
            范围。$腕表(attrs.ngModel,功能(为newValue,属性oldValue){
                //ngModel.$setViewValue(newValue +)!;                如果(==为newValue富)
                {
                    ngModel $ setViewValue(属性oldValue)。
                    / *
                        我需要这个渲染调用,以更新的输入框;这可以吗?
                        我最好的猜测是,设置新老= prevents一个肮脏的检查可能会触发$渲染()
                    * /
                    。ngModel $渲染();
                }
            });
        }
    };
});函数x($范围){
    $ scope.test ='在这里的价值;
}


解决方案

  

我们的这里最好的猜测是,旧的设置==新的prevents的发生。

脏检查

在除权pression的价值它监听到的变化观察者监听器只调用。但因为你改变了模式恢复到previous价值,它不会再次调用,因为它就像值没有改变。但是,要小心:改变观察家监控里面的属​​性相同的属性可能会导致一个无限循环的价值


  

但它不会设置新的值后更新DOM(和你在浏览器中看到的),直到我明确地调用ngModel。$渲染()。


这是正确的。 $ setViewValue 设置模型的价值,如果它是由视图更新,但是你需要 $渲染来有效地调用呈现基于(新)模型的价值的看法。请查看这种讨论了解详情。

最后,我想你应该接近你的问题的不同方式。您可以使用 $解析器 NgModelController 的属性来验证,而不是使用一个观察者的用户输入,

 链接:功能(范围,元素,ATTRS,ngModel){
  如果(ngModel!)回报;  ngModel。$ parsers.unshift(功能(viewValue){
    如果(viewValue ==='富'){
      VAR CurrentValue的= ngModel $ modelValue。
      ngModel $ setViewValue(CurrentValue的)。
      。ngModel $渲染();
      返回CurrentValue的;
    }
    其他
      返回viewValue;
  });
}

我改变了自己的的jsfiddle脚本的使用code以上。

\r
\r

angular.module('myDirective',[])\r
.directive('myDirective',函数(){\r
  返回{\r
    限制:'A',\r
    终端:真实,\r
    要求:ngModel\r
    链接:功能(范围,元素,ATTRS,ngModel){\r
      如果(ngModel!)回报;\r
\r
      ngModel。$ parsers.unshift(功能(viewValue){\r
        如果(viewValue ==='富'){\r
          VAR CurrentValue的= ngModel $ modelValue。\r
          ngModel $ setViewValue(CurrentValue的)。\r
          。ngModel $渲染();\r
          返回CurrentValue的;\r
        }\r
        其他\r
          返回viewValue;\r
      });\r
    }\r
  };\r
});\r
\r
函数x($范围){\r
  $ scope.test ='在这里的价值;\r
}

\r

&LT;脚本SRC =htt​​ps://ajax.googleapis.com/ajax /libs/angularjs/1.2.23/angular.min.js\"></script>\r
&LT; H1&GT;喷火战机乐队&LT; / H1&GT;\r
我讨厌富,只是尝试,并在框中键入它。\r
&LT; D​​IV NG-应用=myDirectiveNG控制器=X&GT;\r
  &LT;输入类型=文本NG模型=测试我-指令&GT;\r
  &LT; BR /&GT;\r
  型号:{{测试}}\r
&LT; / DIV&GT;

\r

\r
\r

I made a directive designed to be attached to an element using the ngModel directive. If the model's value matches something the value should then set to the previous value. In my example I'm looking for "foo", and setting it back to the previous if that's what's typed in.

My unit tests passed fine on this because they're only looking at the model value. However in practice the DOM isn't updated when the "put back" triggers. Our best guess here is that setting old == new prevents a dirty check from happening. I stepped through the $setViewValue method and it appears to be doing what it ought to. However it won't update the DOM (and what you see in the browser) until I explicitly call ngModel.$render() after setting the new value. It works fine, but I just want to see if there's a more appropriate way of doing this.

Code is below, here's a fiddle with the same.

angular.module('myDirective', [])
    .directive('myDirective', function () {
    return {
        restrict: 'A',
        terminal: true,
        require: "?ngModel",
        link: function (scope, element, attrs, ngModel) {
            scope.$watch(attrs.ngModel, function (newValue, oldValue) {
                //ngModel.$setViewValue(newValue + "!");   

                if (newValue == "foo")
                {
                    ngModel.$setViewValue(oldValue);   
                    /* 
                        I Need this render call in order to update the input box; is that OK?
                        My best guess is that setting new = old prevents a dirty check which would trigger $render()
                    */
                    ngModel.$render();
                }
            });
        }
    };
});

function x($scope) {
    $scope.test = 'value here';
}

解决方案

Our best guess here is that setting old == new prevents a dirty check from happening

A watcher listener is only called when the value of the expression it's listening to changes. But since you changed the model back to its previous value, it won't get called again because it's like the value hasn't changed at all. But, be careful: changing the value of a property inside a watcher monitoring that same property can lead to an infinite loop.

However it won't update the DOM (and what you see in the browser) until I explicitly call ngModel.$render() after setting the new value.

That's correct. $setViewValue sets the model value as if it was updated by the view, but you need to call $render to effectively render the view based on the (new) model value. Check out this discussion for more information.

Finally, I think you should approach your problem a different way. You could use the $parsers property of NgModelController to validate the user input, instead of using a watcher:

link: function (scope, element, attrs, ngModel) {
  if (!ngModel) return;

  ngModel.$parsers.unshift(function(viewValue) {
    if(viewValue === 'foo') {                 
      var currentValue = ngModel.$modelValue;
      ngModel.$setViewValue(currentValue);
      ngModel.$render(); 
      return currentValue;
    }
    else 
      return viewValue;
  });
}

I changed your jsFiddle script to use the code above.

angular.module('myDirective', [])
.directive('myDirective', function () {
  return {
    restrict: 'A',
    terminal: true,
    require: "?ngModel",
    link: function (scope, element, attrs, ngModel) {
      if (!ngModel) return;

      ngModel.$parsers.unshift(function(viewValue) {
        if(viewValue === 'foo') {                 
          var currentValue = ngModel.$modelValue;
          ngModel.$setViewValue(currentValue);
          ngModel.$render(); 
          return currentValue;
        }
        else 
          return viewValue;
      });
    }
  };
});

function x($scope) {
  $scope.test = 'value here';
}

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<h1>Foo Fighter</h1>
I hate "foo", just try and type it in the box.
<div ng-app="myDirective" ng-controller="x">
  <input type="text" ng-model="test" my-directive>
  <br />
  model: {{test}}
</div>

这篇关于AngularJS - 在更改模型值的指令,为什么我要叫$渲染?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆