繁体   English   中英

Angular Directive的模板绑定不会更新

[英]Angular Directive's template binding doesn't update

我在这里设置了一个指令http://jsfiddle.net/screenm0nkey/8Cw4z/3 ,它有两个绑定到同一个scope属性,但由于某种原因,当模型更改时,指令的template属性中的绑定不会更新(输入后输入)。

<test>
    <h3>Inner {{count}}</h3>
    <input type="text" ng-model="count">
</test>

var App = angular.module('App', []);
App.directive('test', function() {
    return {
      restrict: 'E',
      replace: true,
      transclude: true,
      template: "<h1>Outer{{count}} <div ng-transclude></div></h1>",
      controller: function ($scope) {
        $scope.count = 1;
      }
    };
  });

但是,如果我在标记中移动输入位置,它就可以工作,并且两个绑定都会更新。

<input type="text" ng-model="count">
<test>
     <h3>Inner {{count}}</h3>
</test>

http://jsfiddle.net/screenm0nkey/dCvZk/3

任何人都可以解释为什么包含绑定的输入的位置会影响绑定。 我假设在摘要循环期间,无论标记的位置如何,都将更新两个绑定的观察者。

非常感谢

对我来说,这似乎纯粹是一个范围问题。 让我们看一下两者生成的标记:

不工作:

<body ng-app="App" class="ng-scope">
  <h1 class="ng-binding">Outer1 <div ng-transclude="">
    <h3 class="ng-scope ng-binding">Inner 1</h3>
    <input type="text" ng-model="count" class="ng-scope ng-pristine ng-valid">
    </div>
  </h1>
</body>

工作:

<body ng-app="App" class="ng-scope">
  <input type="text" ng-model="count" class="ng-valid ng-dirty">
  <h1 class="ng-binding">Outer <div ng-transclude="">
    <h3 class="ng-scope ng-binding">Inner </h3>
    </div>
  </h1>
</body>

ng-scope类是Angular声明新范围的有用标记。

您可以通过标记看到,在工作示例中, count属性都包含在附加到bodyscope 因此,在这种情况下, directive范围是body范围的子节点(因此可以访问它)。

但是,在不起作用的示例中, Outer1属性位于input所在范围之外。

Angular Scope文档涵盖了这一点。 范围以层次结构排列,子范围可以访问父范围(但不是相反):

应用程序可以有多个范围,因为某些指令会创建新的子范围(请参阅指令文档以查看哪些指令创建新范围)。 创建新范围时,它们将作为其父范围的子项添加。 这会创建一个树形结构,与它们所附着的DOM平行

角度范围层次

长话短说 - 正如其他人所说,这是一个范围问题。 使用“ng-transclude”指令创建一个新范围。 创建新作用域时,旧作用域中的可以在新作用域中访问(因此是第一个替换),但之后只会更新旧/新作用域之间共享的对象。 这就是为什么使用对象可以工作,但使用值不会。

在您的情况下,将输入字段放在ng-transclude内部会导致仅编辑该范围中的值,而不是父范围中的值(这是“test”指令的计数从中拉出的位置)。

顺便说一句,这可能是中继器(ng-repeat)以及其他指令的问题。 最好使用诸如“ Batarang ”之类的工具来查找诸如此类的问题。 它允许您查看每个范围内的内容,并确定屏幕未显示“正确”数据的原因。 希望有助于进一步解释!

这是一个解决方法

$scope.count更改为

$scope.helper = {
    count: 1
}

并重构其余部分。

请查看此视频以获取解释。

由于在范围上创建属性与实际使用绑定到范围的对象之间的区别(特别是当转换创建新的子scopr时),顺序很重要。 最佳做法是使用范围上的对象,并在范围问题与指令和转换相关时将属性绑定到该对象。

如果您将代码更改为此代码,它将按您的预期工作,并且订单无关紧要。 请注意,我正在创建一个范围对象并将计数作为该对象的属性。

<test>
    <h3>Inner {{data.count}}</h3>
    <input type="text" ng-model="data.count"/>
</test>

var App = angular.module('App', []);

App.directive('test', function() {
    return {
      restrict: 'E',
      replace: true,
      transclude: true,
      template: "<h1>Outer{{data.count}} <div ng-transclude></div></h1>",
      controller: function ($scope) {
          $scope.data = {};
          $scope.data.count = 1;
      }
    };
  });

这是关于这个主题的很棒的教程。 道具到EggHead。 https://egghead.io/lessons/angularjs-the-dot

添加ng-changeinput ,它应该工作。 问题是控制器进入指令不知道count变化。

JS

var App = angular.module('App', []);

App.directive('test', function () {        
    return {
        restrict: 'E',
        replace: true,
        transclude: true,
        template: "<h1>Outer {{this.count}} <div ng-transclude></div></h1>",
        controller: function ($scope) {
            $scope.count = 1;

            $scope.onChange = function(count){          
              $scope.count = count;          
            }
        }       
    };
});

HTML

<test>
     <h3>Inner {{count}}</h3>
    <input type="text" ng-model="count" ng-change="onChange(count)">        
</test>

演示小提琴

这是一个范围问题。

$scope.count = 1; 将属性count添加到<test>所在的范围。让我们将其称为父范围。

ng-transclude创建一个新范围,让我们称之为子范围。 当计算<h3>Inner {{count}}</h3> ,子范围没有属性count因此从父范围读取。

<input type="text" ng-model="count">将输入值绑定到子范围中的属性count 一旦你输入了东西,如果它还没有,那么它就会被创造出来。 从这一点开始, <h3>Inner {{count}}</h3>从子范围获取其值。

angular中的范围是简单的JavaScript对象,并通过原型连接到它们的父对象。 因此,在您输入内容之前,子范围看起来像

{
  prototype: { // = parent scope
     count: 1
  }
}

当您将值更改为5时,范围看起来像

{
  count: 5,
  prototype: { // = parent scope
     count: 1
  }
}

因为数据绑定的作用类似于scope.count = 5

似乎我们无法覆盖这一点,因为ngTransclude将直接使用$transclude ngTransclude函数。 请参阅: https//github.com/angular/angular.js/blob/master/src/ng/directive/ngTransclude.js

和: http//docs.angularjs.org/api/ng。$ compile

transcludeFn - 预先绑定到正确的转换范围的转换链接函数。 范围可以由可选的第一个参数覆盖。 这与指令控制器的$ transclude参数相同。 function([scope],cloneLinkingFn)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM