我在这里设置了一个指令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
任何人都可以解释为什么包含绑定的输入的位置会影响绑定。我假设在摘要循环期间,无论标记的位置如何,两个绑定的观察者都会被更新。
非常感谢
答案 0 :(得分:2)
对我来说,这似乎纯粹是一个范围问题。让我们看一下两者生成的标记:
无效:
<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
属性都附加在scope
附加的body
中。因此,在这种情况下,directive
范围是body
范围的子级(因此可以访问它)。
但是,在不起作用的示例中,Outer1
属性位于input
所在范围之外。
Angular Scope documentation涵盖了这一点。范围以层次结构排列,子范围可以访问父范围(但不是相反):
应用程序可以有多个范围,因为有些指令 创建新的子范围(请参阅指令文档以查看哪些 指令创建新范围)。创建新范围时,它们是 添加为其父范围的子项。这会创建一个树结构 这与它们所附着的DOM相似
答案 1 :(得分:2)
长话短说 - 正如其他人所说,这是一个范围问题。使用“ng-transclude”指令创建一个新范围。创建新作用域时,旧作用域中的值将在新作用域中可访问(因此是第一个替换),但之后只会更新旧/新作用域之间共享的对象。这就是为什么使用对象会起作用,但是使用值不会。
在您的情况下,将输入字段放在ng-transclude中会导致仅编辑该范围中的值,而不是父范围中的值(这是“test”指令的计数从中拉出的位置)
顺便说一句,这可能是中继器(ng-repeat)以及其他指令的问题。最好使用诸如“Batarang”之类的工具来查找此类问题。它允许您查看每个范围内的内容,并确定屏幕未显示“正确”数据的原因。希望有助于进一步解释!
答案 2 :(得分:1)
答案 3 :(得分: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
答案 4 :(得分:1)
将ng-change
添加到input
,它应该有效。问题是controller into指令不知道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>
演示 Fiddle
答案 5 :(得分:1)
这是一个范围问题。
$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
。
答案 6 :(得分:0)
似乎我们无法覆盖此问题,因为ngTransclude
将直接使用$transclude
函数。
请参阅: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)。