2016-04-27 9 views
3

Я хочу создать компонент «my-form-group», состоящий из метки, любого типа элемента ввода (ввод, флажок, ...) и 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>` 
}) 
... 

Я хочу использовать состояние проецируемого компонента, чтобы скрыть или показать «необходимую» звездочку и 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; 
} 

Теперь вы можете просто изменить входы для каждого поля ввода, которые вы используете, и он покажет, что * asterick, если требуется управление. (Надеюсь, что это то, что вы хотели)

** Код не компилируется

+0

Что бы вы использовать для запроса '@ContentChildren()' ? В качестве «селектора» можно использовать AFAIK только переменную шаблона или тип компонента/директивы. –

+0

Вам нужно будет ввести 'ElementRef', а затем вы можете использовать' this.elementRef.nativeElement.querySelectorAll (...) ', чтобы иметь возможность использовать селекторы CSS. –

+0

, но это не даст 'ComponentRef' право? так что никакой пользы от использования ElementRef' –

3

Вы можете использовать @ContentChild(), где вам нужно передать имя переменной шаблона или тип компонента или директивы.
Недостатком переменной шаблона является то, что пользователь вашего компонента должен применять его с правильным именем, что делает ваш компонент более сложным в использовании.
Он похож на компонент или директиву, где используется родительский компонент (где используется <my-form-group>), необходимо добавить providers: [MyProjectionDirective], что также громоздко.

2-й подход позволяет обходного пути

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

Когда то MyProjectionDirective имеет селектор, который соответствует прогнозируемому содержанию (как selector: 'input'), то директива применяется к каждому входному элементу, и вы можете запросить его. Недостатком является то, что директива затем также применяется к любому другому элементу ввода в вашем Угловом приложении. Вы также не получаете экземпляр компонента проецируемого компонента, но директиву. Вы можете сообщить @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

См. комментарии к вашему ответу. –

Смежные вопросы