Повторное использование компонентов в формах, управляемых моделью angular2

Я новичок в angular2, и в течение последних нескольких дней я пытался создавать повторно используемые компоненты формы, используя формы, управляемые моделью.

Допустим, у нас есть компонент componentA.component.ts

@Component({
    selector: 'common-a',
    template: `
    <div [formGroup]="_metadataIdentifier">
        <div class="form-group">
        <label>Common A[1]</label>
        <div>
            <input type="text" formControlName="valueA1">
            <small>Description 1</small>
        </div>
        <div class="form-group">
        <label>Common A[2]</label>
        <div>
            <input type="text" formControlName="valueA2">
            <small>Description 2</small>
        </div>
    </div>
    `
})


export class ComponentA implements OnInit{

    @Input('group')
    public myForm: FormGroup;

    constructor(private _fb: FormBuilder) {
    }

    ngOnInit() {
        this.myForm = this._fb.group({
            valueA1 : ['', [Validators.required]],
            valueA2 : ['', [Validators.required]],
        });
    }
}

И компонент B componentB.component.ts

@Component({
    selector: 'common-b',
    template: `
    <div [formGroup]="_metadataIdentifier">
        <div class="form-group">
        <label>Common B</label>
        <div>
            <input type="text" formControlName="valueB">
            <small>Description</small>
        </div>
    </div>
    `
})


export class ComponentB implements OnInit{

    @Input('group')
    public myForm: FormGroup;

    constructor(private _fb: FormBuilder) {
    }

    ngOnInit() {
        this.myForm= this._fb.group({
            valueB : ['', [Validators.required]]
        });
    }
}

Мой вопрос заключается в том, как я могу составить форму, используя эти два подкомпонента, не перемещая управление входами в основной компонент. Например main.component.ts

@Component({
    selector: 'main',
    template: `
    <form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm.value)">
        <div>
            <common-a [group]="formA"></common-a>
            <common-b [group]="formB"></common-b>
            <div>
                <button>Register!</button>
            </div>
        </div>
    </form>
    `
})


export class Main implements OnInit{

    @Input('group')
    public myForm: FormGroup;

    public formA : FormGroup;

    public formB : FormGroup;

    constructor(private _fb: FormBuilder) {
    }

    ngOnInit() {
        this.myForm = this._fb.group({
            //how can I compose these two sub forms here
            //leaving the form control names agnostic to this component
        });
    }
}

Идея, стоящая за этой идеей, состоит в том, чтобы построить множество сложных форм, которые имеют общие строительные блоки.

То есть я не хочу, чтобы мой компонент Main знал имена formControlNames [valueA1,valueA2,valueB], но автоматически вставлял их и обновлял/проверял в группе форм верхнего уровня.

Любые идеи или точки в правильном направлении будут полезны.


person stefanos    schedule 30.11.2016    source источник


Ответы (1)


Этого можно достичь, передав наш верхний уровень FormGroup дочернему компоненту и заставив дочерний компонент добавить себя на более высокий уровень FormGroup, используя formGroupName таким образом, что верхний уровень FormGroup практически ничего не должен знать о нижних уровнях:

main.component.ts

template: `<...>
    <common-a [parentForm]="myForm"></common-a>
    <...>

Мы также избавимся от объявлений formA, formB, так как они больше не используются.

component-a.component.ts [formGroup] — это наша родительская группа, formGroupName — это то, как мы будем идентифицировать и присоединять элементы управления компонента как группу для работы в целом (они будут вложены внутри родительской группы).

@Component({<...>
template: `
<div [formGroup]="parentForm">
    <div class="form-group">
    <label>Common A[1]</label>
    <div formGroupName="componentAForm">
        <input type="text" formControlName="valueA1">
        <small>Description 1</small>
    </div>
    <div class="form-group">
    <label>Common A[2]</label>
    <div formGroupName="componentAForm">
        <input type="text" formControlName="valueA2">
        <small>Description 2</small>
    </div>
</div>`
})

export class ComponentA implements OnInit {
     @Input() parentForm: FormGroup;
     componentAForm: FormGroup;

     constructor(private _fb: FormBuilder) {}

     ngOnInit() {
         this.componentAForm = this._fb.group({
             valueA1: ['', Validators.required],
             valueA2: ['', Validators.required]
         });

         this.parentForm.addControl("componentAForm", this.componentAForm);
     }
}

Вот плункер (обратите внимание, что я сделал здесь компонент B немного более динамичным, просто чтобы посмотреть, можно ли это сделать, но вышеприведенная реализация for в равной степени применима и к B): http://plnkr.co/edit/fYP10D45pCqiCDPnZm0u?p=preview

person silentsod    schedule 30.11.2016
comment
Большое спасибо, это было действительно полезно и открыло глаза :) - person stefanos; 01.12.2016
comment
Новичок в angular и сразу начал с форм, управляемых моделями. Из любопытства, является ли этот метод совместного использования полей FormGroup рекомендуемым подходом или обходным путем? Я создаю сложную систему и стараюсь сосредоточиться на разработке небольших компонентов, а затем повторно использовать их в отношениях родитель-потомок (уровни 4-5). - person Raf; 24.09.2017