2016-04-27 83 views
3

我想創建一個「my-form-group」組件,它由一個標籤,任何類型的輸入元素(input,checkbox,...)和一個用於驗證結果的div組成。 我想使用內容投影在標籤後插入輸入。事情是這樣的:在angular2中訪問任意子節點

<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>` 
}) 
... 

我想用投影組件的狀態,以隱藏或顯示「必需的」星號和驗證股利。據我所知,可以通過使用@ContentChild()ngAfterContentInit()訪問投影組件,但我認爲,我必須有一個特殊的組件才能使用它。

如果我不知道確切的組件,訪問投影組件的控制器的最佳方式是什麼?

回答

2

通過你的控制,這樣

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

現在你可以改變你使用的每個輸入字段中輸入,它會顯示*如果需要控制,請插入星號。 (希望這是你想要的)

**代碼不編譯

+0

你會用什麼來查詢'@ContentChildren()' ? AFAIK只能將模板變量或組件/指令類型用作「選擇器」。 –

+0

你需要注入'ElementRef',然後你可以使用'this.elementRef.nativeElement.querySelectorAll(...)'來使用CSS選擇器。 –

+0

但這不會給'ComponentRef'權利?所以使用'ElementRef' –

3

您可以使用@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

+0

如果使用'selector :'input.someclass''?是否允許 –

+0

查看您的答案評論。 –