javascript 嵌套指令中的 AngularJS 双向数据绑定
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17181907/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AngularJS Two-way Data Binding in Nested Directives
提问by princjef
Please let me know if you need more information or want me to clarify anything. I have tried a lot of different things to figure this out but haven't found a solution.
如果您需要更多信息或希望我澄清任何事情,请告诉我。我尝试了很多不同的方法来解决这个问题,但还没有找到解决方案。
I'm relatively new to angularJS and I am trying to build an app with several layers of data. I have some basic user information stored in the scope of the body on controller PageController. I then have a settings form that loads in using $routeParams (with controller SettingsController) that includes a couple of custom directives for templating purposes. Since the directives are nested, I am using transclusion to load the second one inside of the first. This all seems to be working alright.
我对 angularJS 比较陌生,我正在尝试构建一个具有多层数据的应用程序。我有一些基本的用户信息存储在控制器 PageController 的主体范围内。然后我有一个使用 $routeParams(带有控制器 SettingsController)加载的设置表单,其中包含几个用于模板目的的自定义指令。由于指令是嵌套的,我使用嵌入来加载第一个内部的第二个。这一切似乎都正常。
My problem is that I am trying to reference the field user.firstname
from within the innermost directive and want to use two-way databinding to allow changes made to the textbox to cause the value at the PageController scope to change as well. I know that a lot of these kinds of problems are caused by using primitives in ng-model, but I have tried putting everything within an extra object so that I trigger prototypal inheritance to no avail. What am I doing wrong here?
我的问题是我试图user.firstname
从最里面的指令中引用该字段,并希望使用双向数据绑定来允许对文本框所做的更改以导致 PageController 范围内的值也发生更改。我知道很多这类问题是由在 ng-model 中使用原语引起的,但是我尝试将所有内容都放在一个额外的对象中,以便触发原型继承无济于事。我在这里做错了什么?
Here's a JSFiddleof my code, stripped down as much as possible to isolate the problem. In this example, if I type in the outside textbox, which is directly on the PageController scope, it will modify the inner textbox until that textbox is modified, upon which the connection is broken. This seems just like the problem of using primitives as described in other questions, but I can't figure out where the issue is here.
这是我的代码的JSFiddle,尽可能精简以隔离问题。在这个例子中,如果我输入外部文本框,它直接在 PageController 范围内,它将修改内部文本框,直到修改该文本框,然后连接断开。这似乎就像其他问题中描述的使用原语的问题,但我无法弄清楚问题出在哪里。
HTML:
HTML:
<body class="event-listing" ng-app="app" ng-controller="PageController">
<div class="listing-event-wrap">
<input type="text" ng-model="user.firstname" />
<div ng-controller="SettingsController">
<section block title="{{data.updateInfo.title}}" description="{{data.updateInfo.description}}">
<div formrow label="{{data.updateInfo.labels.firstname}}" type="textInput" value="user.firstname"></div>
</section>
</div>
</div>
</body>
Angular Directives:
角度指令:
app.directive('formrow', function() {
return {
scope: {
label: "@label",
type: "@type",
value: "=value"
},
replace: true,
template: '<div class="form-row">' +
'<div class="form-label" data-ng-show="label">{{label}}</div>' +
'<div class="form-entry" ng-switch on="type">' +
'<input type="text" ng-model="value" data-ng-switch-when="textInput" />' +
'</div>' +
'</div>'
}
});
app.directive('block', function() {
return {
scope: {
title: "@title",
description: "@description"
},
transclude: true,
replace: true,
template: '<div class="page-block">' +
'<h2 data-ng-show="title">{{title}}</h2>' +
'<p class="form-description" data-ng-show="description">{{description}}</p>' +
'<div class="block-inside" data-ng-transclude></div>' +
'</div>'
}
});
Angular Controllers:
角度控制器:
app.controller("PageController", function($scope) {
$scope.user = {
firstname: "John"
};
});
app.controller("SettingsController", function($scope) {
$scope.data = {
updateInfo: {
title: "Update Your Information",
description: "A description here",
labels: {
firstname: "First Name"
}
}
}
});
采纳答案by Nir
I'm sorry for the previous code. Try this instead: http://jsfiddle.net/CxNc2/2/
我很抱歉之前的代码。试试这个:http: //jsfiddle.net/CxNc2/2/
Instead of passing the actual value, I'm now passing the object + a pointer to the correct value inside. I added 'refobject' here:
我现在没有传递实际值,而是传递对象 + 指向内部正确值的指针。我在这里添加了“refobject”:
<body class="event-listing" ng-app="app" ng-controller="PageController">
<div class="listing-event-wrap">
<input type="text" ng-model="user.firstname" />
<div ng-controller="SettingsController">
<section block title="{{data.updateInfo.title}}" description="{{data.updateInfo.description}}">
<div formrow label="{{data.updateInfo.labels.firstname}}" type="textInput" refobj='user' value="firstname"></div>
</section>
</div>
</div>
</body>
and I added refobj + value here:
我在这里添加了 refobj + value:
app.directive('formrow', function() {
return {
scope: {
label: "@label",
type: "@type",
value: "@value",
refobj: "="
},
replace: true,
template: '<div class="form-row">' +
'<div class="form-label" data-ng-show="label">{{label}}</div>' +
'<div class="form-entry" ng-switch on="type">' +
'<input type="text" ng-model="refobj[value]" data-ng-switch-when="textInput" />' +
'</div>' +
'</div>'
}
回答by Dan
Since the textbox in the directive uses a primitive instead of an object for its model (ng-model="value"
rather than ng-model="someobj.somevalue"
), its model is created only on the local scope and the parent does not have access to it.
由于指令中的文本框对其模型(ng-model="value"
而不是ng-model="someobj.somevalue"
)使用原语而不是对象,因此其模型仅在本地范围内创建,父级无权访问它。
The fix is to define the directive textbox model using the dot ruleas an object property:
解决方法是使用点规则作为对象属性定义指令文本框模型:
ng-model="value.firstname"
Then pass the whole user
object into the directive instead of just the primitive property:
然后将整个user
对象传递给指令,而不仅仅是原始属性:
<div formrow ... value="user"></div>
回答by Joe.wang
The problem is caused by ng-switch
, From the doc Understanding scopefrom git.
问题是由ng-switch
, 从git的文档理解范围引起的。
ng-switch scope inheritance works just like ng-include. So if you need 2-way data binding to a primitive in the parent scope, use $parent, or change the model to be an object and then bind to a property of that object. This will avoid child scope hiding/shadowing of parent scope properties.
ng-switch 作用域继承就像 ng-include 一样工作。因此,如果您需要对父作用域中的原语进行 2 向数据绑定,请使用 $parent,或者将模型更改为对象,然后绑定到该对象的属性。这将避免父范围属性的子范围隐藏/阴影。
so if you type some text in the textbox.
below code will be executed for the ng-switch
scope.
所以如果你在文本框中输入一些文本。下面的代码将针对ng-switch
范围执行。
$scope.value="the text you typed"
$scope.value="the text you typed"
So it will not consult the prototype chain to search value
.this will created a new property for ng-switch
scope.
所以它不会查询原型链来搜索。这value
将为ng-switch
范围创建一个新属性。
How to testify it ?
如何作证?
If you change value
to $parent.value
. everything will work fine. because in the ng-switch
for the primitive type (angularjs would recognize the value
as primitive type if there is no dot )$parent
will refer to formrow
directive scope.
如果您更改value
为$parent.value
. 一切都会好起来的。因为在ng-switch
原始类型中(value
如果没有点,angularjs 会将原始类型识别为原始类型)$parent
将引用formrow
指令范围。
Try to remove the ng-switch
or do as the doc says. the problem will disappear.
尝试删除ng-switch
或 按照文档说的去做。问题就会消失。
And more important, the document recommend us always use a dot .
to refer the model when apply a bi-directional binding.
更重要的是,该文档建议我们.
在应用双向绑定时始终使用点来引用模型。
If I said something wrong . Please kindly correct me and make it right .thanks.
如果我说错了。请纠正我并使其正确。谢谢。