在 angular2 中访问任意 child

Accessing arbitrary child in angular2

我想创建一个 "my-form-group" 组件,由标签、任何类型的输入元素(输入、复选框等)和用于验证结果的 div 组成。 我想使用内容投影在标签后插入输入。像这样:

<form [ngFormModel]="myForm" (ngSubmit)="onSubmit()">    
  <my-form-group>
    <input type="text" 
           class="form-control"
           [ngFormControl]="myForm.controls['name']">
  </my-form-group>
<form>

组件可能如下所示:

@Component({
  selector: 'my-form-group',
  template: `
    <div class="form-group">
      <label for="name">Name<span [ngIf]="name.required"> *</span></label>
      <ng-content></ng-content>
      <div [hidden]="name.valid || name.pristine" class="alert alert-danger">
        Please check your input
      </div>
    </div>`
})
...

我想使用投影组件的状态来隐藏或显示 "required" 星号和验证 div。据我所知,可以使用 @ContentChild()ngAfterContentInit() 访问投影组件,但我认为,我必须有一个特殊的组件才能使用它。

如果我不知道确切的组件,访问投影组件的控制器的最佳方式是什么?

像这样传递你的控制权

@Component({
    selector: 'parent',
    directives: [MyFormGroup],
    template: `
               <form [ngFormModel]="myForm" (ngSubmit)="onSubmit()">    
                   <my-form-group [control]="myForm.controls['name']" controlId="name">
                     <input type="text" 
                      class="form-control" ngControl="name">
                   </my-form-group>
               <form>

            `
})
export class Parent {
    @ContentChildren(MyFormGroup) children: QueryList<MyFormGroup>;
    ngAfterContentInit() {
        console.log(this.children);
    }
}

在你的组件中

@Component({
  selector: 'my-form-group',
  template: `
<div class="form-group">
  <label for="{{controlId}}"> {{controlId}} <span [ngIf]="control.hasError('required')"> *</span></label>
  <ng-content></ng-content>
  <div [hidden]="control.valid || control.pristine" class="alert alert-danger">
    Please check your input
  </div>
</div>`
})
export class MyFormGroup {
      @Input control: Control;
      @Input controlId: string;
}

现在您只需更改您使用的每个输入字段的输入,如果需要控制,它会显示*星号。 (希望这就是你想要的)

**代码未编译

您可以在需要传递模板变量名称或组件或指令类型的地方使用@ContentChild()
模板变量的缺点是,您的组件的用户需要使用正确的名称来应用它,这会使您的组件更难使用。
对于父组件(使用<my-form-group>)需要添加providers: [MyProjectionDirective]的组件或指令类似,这同样很麻烦。

第二种方法允许解决方法

provide(PLATFORM_DIRECTIVES, {useValue: [MyProjectionDirective], multi: true})

MyProjectionDirective 有一个与投影内容匹配的选择器(如 selector: 'input')时,指令将应用于每个输入元素,您可以查询它。不利的一面是,该指令随后还会应用于 Angular 应用程序中的任何其他输入元素。 您也没有得到投影组件的组件实例,而是指令。您可以告诉 @ContentChild() 获取组件实例,但为此您需要提前知道类型。

因此,使用模板变量的方法似乎是最佳选择:

使用模板变量的示例

@Component({
    selector: 'my-input',
    template: `
    <h1>input</h1>
    <input>
    `,
})
export class InputComponent {
}

@Component({
    selector: 'parent-comp',
    template: `
    <h1>Parent</h1>
    <ng-content></ng-content>
    `,
})
export class ParentComponent {
  @ContentChild('input') input;

  ngAfterViewInit() {
    console.log(this.input);
    // prints `InputComponent {}`
  }
}


@Component({
    selector: 'my-app',
    directives: [ParentComponent, InputComponent],
    template: `
    <h1>Hello</h1>
    <parent-comp><my-input #input></my-input></parent-comp>
    `,
})
export class AppComponent {
}

Plunker example