我有点困惑。 使用ngModel我可以执行以下操作:
import {NgModel} from "angular2/common";
@Component({
selector: "test",
template: `<input tpye="text" [(ngModel)]="strInObj.str"> {{strInObj|json}}`,
directives: [NgModel]
})
class Test{
strInObj: {str: string} = {str: "this is a string"};
}
现在,当我输入输入时,strInObj.str
会更新。我对此感到困惑,因为据我所知,字符串是不可变的,并且无法找到引用的父级。
在这种情况下,我直接传递str
属性,这意味着ngModel
获取对字符串的引用。如果它“更改”该引用上的字符串,则会创建一个新字符串,因此不会更改strInObj.str
指向的原始字符串。至少这是我的理解
并且无法找到传递给ngModel的引用的父级(没有像str.parent()
这样的概念,它会返回strInObj
)
那他们怎么做呢?我试图理解ts和js的来源,但是......好吧,我在这里。
我尝试构建一个类似的指令,但最终只能传递包裹字符串的对象,我没有找到一种方法来直接传递str
属性时修改原始对象....(在示例中,我将strInObj
传递给我的指令,然后该指令将与传递的对象的str
属性一起使用,这可以正常工作。
如果有人可以帮我解开这个问题,我会很高兴。)
修改
In this plunker我有自定义指令StrDirective
和带有NgModel指令的输入字段。两者都具有相同的绑定exampleStr
,它在简单的范围内输出
现在,当我在输入中输入文本时,您可以看到exampleStr
正在更新。这是预期的行为。我知道这很有用。
单击时StrDirective
更新其绑定。您可以看到它更新了字符串的“工作副本”,但exampleStr
未更新
我的问题现在是:他们是如何做到的/如何在没有将其包装在对象中的情况下获得更新ExampleStr
的指令?
答案 0 :(得分:6)
在Javascript中,所有字符串都是不可变的。当有人输入输入字段时,它会更新&#34;工作副本&#34;字符串,以便工作副本指向新的引用。或换句话说,每次字符串更改时,它都是一个新的字符串引用。
当按下一个更改模型的键时,会触发ngModelChange
输出事件,然后使用新引用更新父组件的模型。引用现在是同步的。当你说&#34;修改传递给它的字符串&#34;时,这是不可能的,因为字符串是不可变的。
当存在与模型的双向绑定时:
[(ngModel)]="str"
绑定相当于:
[ngModel]="str" (ngModelChange)="str=$event"
只要@Output
(模型绑定)发生更改,就会触发ngModelChange
str
事件。通过这种方式,引用的更改向上传播到设置了双向模型绑定的所有组件,以便每个模型指向相同的引用。
<强> [编辑] 强>
在更新后的问题的Plnkr中,它显示用户在输入框中键入一个键后正在恢复双向绑定。问题是如何以及为什么?
要了解发生了什么,请查看以下两种情况:
用户点击标签,触发事件处理程序,更改绑定的@Input值
用户在输入框中键入一个键。两个标签都自动重新绑定到同一个参考,双向模型绑定适用于两个标签。
在用户点击标签之前,所有绑定都是同步的:
S1 (app component)
/\
(exampleStr binding) S1 S1 (str component)
在click事件之后,绑定的@Input模型会更改。然后,从根开始进行一轮变化检测,并以深度优先顺序运行到子组件。由于@Input绑定向下传播,因此其他绑定没有任何改变。
在第一个场景中,这是click事件后绑定的状态:
S1 (app component)
/\
(exampleStr binding) S1 S2 (str component)
当用户开始输入具有双向绑定设置的文本框时,会触发ngModelChange
事件,将exampleStr
的值更改为S3
。
S3 (app component)
/\
(exampleStr binding) S3 S2 (str component)
然后启动默认的更改检测策略,该策略从根开始并以深度优先顺序向下运行到子组件。
按下某个键后绑定的状态是:
S3 (app component)
/\
(exampleStr binding) S3 S3 (str component)
如您所见,所有绑定再次同步。默认的更改检测策略检查所有组件;对模型的更改通过组件的@Input
绑定传播,从父节点到子节点的可预测和单向流程。
要了解变更检测的工作原理,请考虑分阶段进行变更检测。这是过度简化的,但它可能有助于您的理解:
注意:Angular使用区域来修补浏览器事件,因此它知道何时触发更改检测。
<强> [编辑] 强>
如果您希望在单击标签时更新消息,请像设置ngModel一样设置双向绑定:
@Input("str") value : string;
@Output("strChange") valueChange:EventEmitter<string> = new EventEmitter();
onClick(){
this.value = "new string";
this.valueChange.next(this.value);
}
HTML
<span [(str)]="exampleStr"></span><br>