2016-04-27 16 views
3

Ich möchte eine "my-form-group" -Komponente erstellen, die aus einem Label, einem beliebigen Eingabeelement (Eingabe, Kontrollkästchen, ...) und einem Div für Validierungsergebnisse besteht. Ich möchte die Inhaltsprojektion verwenden, um die Eingabe nach dem Label einzufügen. Etwas wie folgt aus:Zugriff auf ein beliebiges untergeordnetes Element in angular2

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

Die Komponente könnte wie folgt aussehen:

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

Ich möchte den Status des projizierten Komponente verwenden, um die „erforderlich“ Stern zu verstecken oder zu zeigen, und die Validierung div. Soweit ich weiß, kann eine projizierte Komponente unter Verwendung von @ContentChild() und in ngAfterContentInit() zugegriffen werden, aber ich denke, ich muss eine spezielle Komponente haben, um dies zu verwenden.

Wie kann ich am besten auf den Controller der projizierten Komponente zugreifen, wenn ich die genaue Komponente nicht kenne?

Antwort

2

Fahren Sie mit Kontrolle, wie diese

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

Und in Ihrer Komponente

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

Jetzt können Sie nur die Eingänge für jedes Eingabefeld ändern, die Sie verwenden, und es wird zeigen, dass * Sternchen, wenn Kontrolle erforderlich ist. (Hoffe, das ist, was Sie wollten)

** Code nicht

zusammengestellt
+0

Was würden Sie '@ContentChildren abzufragen verwenden()' ? AFAIK nur eine Template-Variable oder ein Komponenten-/Anweisungstyp kann als "Selektor" verwendet werden. –

+0

Sie müssten 'ElementRef' injizieren und dann' this.elementRef.nativeElement.querySelectorAll (...) 'verwenden, um CSS-Selektoren verwenden zu können. –

+0

aber das würde 'ComponentRef' nicht geben? also keinen Nutzen mit 'ElementRef' –

3

können Sie @ContentChild() verwenden, wo Sie den Namen einer Template-Variable übergeben müssen oder den Typ eines Bauteils oder Richtlinie.
Der Nachteil der Template-Variablen ist, dass der Benutzer Ihrer Komponente sie mit dem richtigen Namen anwenden muss, was die Verwendung Ihrer Komponente erschwert.
Es ist ähnlich für die Komponente oder Richtlinie, wo die Mutterkomponente (wo <my-form-group> verwendet wird) providers: [MyProjectionDirective] hinzugefügt werden muss, die ähnlich umständlich ist.

Der zweite Ansatz ermöglicht eine Abhilfe

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

Wenn dann MyProjectionDirective einen Selektor hat, die den projizierten Inhalt übereinstimmt (wie selector: 'input') dann die Richtlinie für jedes Eingabeelement angelegt wird, und Sie können es abfragen. Der Nachteil ist, dass die Direktive dann auch auf jedes andere Eingabeelement in Ihrer Angular-Anwendung angewendet wird. Sie erhalten auch nicht die Komponenteninstanz der projizierten Komponente, sondern die Anweisung. Sie können @ContentChild() sagen, um die Komponenteninstanz zu erhalten, aber dafür müssten Sie den Typ im Voraus kennen.

Daher scheint es der Ansatz mit dem Template-Variable ist die beste Option:

Beispiel eine Template-Variable

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

was ist, wenn Sie 'selector benutzen : 'input.someclass'' ist erlaubt –

+0

Siehe Kommentare zu deiner Antwort. –

Verwandte Themen