[英]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
属性都包含在附加到body
的scope
。 因此,在这种情况下, directive
范围是body
范围的子节点(因此可以访问它)。
但是,在不起作用的示例中, Outer1
属性位于input
所在范围之外。
Angular Scope文档涵盖了这一点。 范围以层次结构排列,子范围可以访问父范围(但不是相反):
应用程序可以有多个范围,因为某些指令会创建新的子范围(请参阅指令文档以查看哪些指令创建新范围)。 创建新范围时,它们将作为其父范围的子项添加。 这会创建一个树形结构,与它们所附着的DOM平行
长话短说 - 正如其他人所说,这是一个范围问题。 使用“ng-transclude”指令创建一个新范围。 创建新作用域时,旧作用域中的值可以在新作用域中访问(因此是第一个替换),但之后只会更新旧/新作用域之间共享的对象。 这就是为什么使用对象可以工作,但使用值不会。
在您的情况下,将输入字段放在ng-transclude内部会导致仅编辑该范围中的值,而不是父范围中的值(这是“test”指令的计数从中拉出的位置)。
顺便说一句,这可能是中继器(ng-repeat)以及其他指令的问题。 最好使用诸如“ Batarang ”之类的工具来查找诸如此类的问题。 它允许您查看每个范围内的内容,并确定屏幕未显示“正确”数据的原因。 希望有助于进一步解释!
由于在范围上创建属性与实际使用绑定到范围的对象之间的区别(特别是当转换创建新的子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-change
到input
,它应该工作。 问题是控制器进入指令不知道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.