如何在angular2中应用@ViewChildren进行父子沟通
我正在努力理解@ViewChildren()decorator。我创建了一个名为Component-a的组件,它接受用户电子邮件地址。创建了名为“组件B”的父组件,该组件有两个孪生组件(两个组件A)。现在我找到了在线教程,介绍了如何通过使用@Input()和@Output()装饰器合并事件和属性绑定来实现父组件和子组件之间的交互。但是,我们如何使用@ViewChildren()来检查输入的两封电子邮件是否相同并打印出匹配的结果呢如何在angular2中应用@ViewChildren进行父子沟通,angular,typescript,Angular,Typescript,我正在努力理解@ViewChildren()decorator。我创建了一个名为Component-a的组件,它接受用户电子邮件地址。创建了名为“组件B”的父组件,该组件有两个孪生组件(两个组件A)。现在我找到了在线教程,介绍了如何通过使用@Input()和@Output()装饰器合并事件和属性绑定来实现父组件和子组件之间的交互。但是,我们如何使用@ViewChildren()来检查输入的两封电子邮件是否相同并打印出匹配的结果呢 @Component({ selector: 'compo
@Component({
selector: 'component-A'
styleUrls: [],
templateUrl: `<form>
<div>
<fieldset>
<legend>Component A</legend>
<div class="form-horizontal">
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">Email</label>
<div class="col-sm-10">
<input type="email" class="form-control" id="inputEmail3" placeholder="Email">
</div>
</div>
</fieldset>
})
export class ComponentA {
}
@组件({
选择器:“组件A”
样式URL:[],
模板URL:`
A部分
电子邮件
})
导出类组件A{
}
现在我有一个组件B:
@Component({
selector: 'component-B',
styleUrls: [],
templateUrl: `
<form>
<div>
<fieldset>
<legend>Parent Component</legend>
<div class="form-horizontal">
<div class="form-group">
<label for="1" class="col-sm-2 control-label">1</label>
<div class="col-sm-10">
<component-A></component-A>
</div>
<div class="form-group">
<label for="2" class="col-sm-2 control-label">2</label>
<div class="col-sm-10">
<component-A></component-A>
</div>
</div>
</div>
</fieldset>
</div>
</form>
})
export class Parent {
}
@组件({
选择器:'component-B',
样式URL:[],
模板URL:`
父组件
1.
2.
})
导出类父类{
}
有关更多详细信息,请参阅
有关更多详细信息,请参见我想尝试一下这个答案,因为我最近经历了这个问题,需要进行大量研究才能完全理解。Angular2中的变化检测流非常强大,但也非常不直观。我将回答你的问题,然后再谈一些细节
@ViewChildren
和AfterViewChecked
正如前面的答案所指定的,您可以使用@ViewChildren
装饰器。我将在上面添加一些额外的代码:
@Component({
template: `
<my-component #component *ngFor="let component of components"></my-component>
`
})
export class Parent implements AfterViewChecked {
private different: boolean = false;
private components: any[] = [];
@ViewChildren("component") componentList: QueryList<MyComponent>;
// Inject the change detector for later use.
constructor(private detector: ChangeDetectorRef) {
}
// Use "AfterViewChecked" hook to check for differences and apply them.
// This will run after every change detection iteration.
ngAfterViewChecked() {
// Figure out if the emails are different.
var email: string;
var different = false;
this.componentList.forEach(component => {
if (email == undefined) {
email = component.email;
}
if (email != component.email) {
different = true;
}
});
// If something changed, save it.
if (different != this.different) {
this.different = different;
// MUST NOTIFY CHANGE DETECTOR.
// This will tell angular to run change detection in the current scope.
//
// Note that we only run it when changes are detected, otherwise it will
// cause an endless loop.
this.detector.detectChanges();
}
}
}
使用@Input
和@Output
完全封装了Angular2更改检测,以便在正常的更改检测周期内检测父级和子级之间的所有更改。你不需要做任何事
有效的变更跟踪
基本上,这种行为的原因是为了有效的变更跟踪。如果您已经在Angular.js(版本1)中开发过,您可能知道更改跟踪是一个混乱的过程。没有一个好的系统知道什么时候发生了变化。您必须相信人们正在调用可怕的作用域。apply()
,它将(如果在根作用域上调用)重新编译整个DOM。这就是经常导致糟糕表现的原因
Angular2已经自动跟踪了相当数量的变更,以便在某些事件发生时执行。悬停、单击、HTTP请求等。不过,它们很聪明,可以使应用程序中的区域发生更改。这意味着变化检测发生在更小的封装单元中,而不总是发生在整个应用程序上
相反
如果您的数据无法使用@Input
和@Output
(例如动态列表或其他原因),则必须使用ViewChildren。如果根据子项的更改检测修改父项状态,则必须让更改检测器知道情况已更改。为什么?因为大多数情况下,子变更检测轮次不会与父变更检测轮次一致。发生这种情况时,您将收到以下错误消息:
angular2.min.js:17异常:表达式“正在加载”HostApp@0:0'在检查后已更改。上一个值:“false”。[isLoading in]中的当前值:“true”HostApp@0:0]
这基本上是说“嘿,数据在我的变化检测周期之外发生了变化”。解决方法是要么修复它,使其在适当的周期内发生变化,要么在工作完成后调用detectChanges()
在Angular advanced documentation网站上可以看到更多关于这一点的信息。我想尝试一下我的答案,因为我最近经历了这一点,需要进行大量的研究才能完全理解。Angular2中的变化检测流非常强大,但也非常不直观。我将回答你的问题,然后再谈一些细节
@ViewChildren
和AfterViewChecked
正如前面的答案所指定的,您可以使用@ViewChildren
装饰器。我将在上面添加一些额外的代码:
@Component({
template: `
<my-component #component *ngFor="let component of components"></my-component>
`
})
export class Parent implements AfterViewChecked {
private different: boolean = false;
private components: any[] = [];
@ViewChildren("component") componentList: QueryList<MyComponent>;
// Inject the change detector for later use.
constructor(private detector: ChangeDetectorRef) {
}
// Use "AfterViewChecked" hook to check for differences and apply them.
// This will run after every change detection iteration.
ngAfterViewChecked() {
// Figure out if the emails are different.
var email: string;
var different = false;
this.componentList.forEach(component => {
if (email == undefined) {
email = component.email;
}
if (email != component.email) {
different = true;
}
});
// If something changed, save it.
if (different != this.different) {
this.different = different;
// MUST NOTIFY CHANGE DETECTOR.
// This will tell angular to run change detection in the current scope.
//
// Note that we only run it when changes are detected, otherwise it will
// cause an endless loop.
this.detector.detectChanges();
}
}
}
使用@Input
和@Output
完全封装了Angular2更改检测,以便在正常的更改检测周期内检测父级和子级之间的所有更改。你不需要做任何事
有效的变更跟踪
基本上,这种行为的原因是为了有效的变更跟踪。如果您已经在Angular.js(版本1)中开发过,您可能知道更改跟踪是一个混乱的过程。没有一个好的系统知道什么时候发生了变化。您必须相信人们正在调用可怕的作用域。apply()
,它将(如果在根作用域上调用)重新编译整个DOM。这就是经常导致糟糕表现的原因
Angular2已经自动跟踪了相当数量的变更,以便在某些事件发生时执行。悬停、单击、HTTP请求等。不过,它们很聪明,可以使应用程序中的区域发生更改。这意味着变化检测发生在更小的封装单元中,而不总是发生在整个应用程序上
相反
如果您的数据无法使用@Input
和@Output
(例如动态列表或其他原因),则必须使用View
<my-component
*ngFor="let component of components"
(emailChanged)="emailChanged(email)">
</my-component>