如何在angular2中应用@ViewChildren进行父子沟通

如何在angular2中应用@ViewChildren进行父子沟通,angular,typescript,Angular,Typescript,我正在努力理解@ViewChildren()decorator。我创建了一个名为Component-a的组件,它接受用户电子邮件地址。创建了名为“组件B”的父组件,该组件有两个孪生组件(两个组件A)。现在我找到了在线教程,介绍了如何通过使用@Input()和@Output()装饰器合并事件和属性绑定来实现父组件和子组件之间的交互。但是,我们如何使用@ViewChildren()来检查输入的两封电子邮件是否相同并打印出匹配的结果呢 @Component({ selector: 'compo

我正在努力理解@ViewChildren()decorator。我创建了一个名为Component-a的组件,它接受用户电子邮件地址。创建了名为“组件B”的父组件,该组件有两个孪生组件(两个组件A)。现在我找到了在线教程,介绍了如何通过使用@Input()和@Output()装饰器合并事件和属性绑定来实现父组件和子组件之间的交互。但是,我们如何使用@ViewChildren()来检查输入的两封电子邮件是否相同并打印出匹配的结果呢

@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>