Search code examples
angularangular-forms

How can I get inputs from a child component to register with my form?


Question as text

When I add an input which is wrapped in a component to my angular form, then the form does not pick up that input as a control belonging to it. That means that e.g. NgForm.valid is unreliable, because it does not contain inputs added from a component.

What is preventing this and what can I do about it?

Question as code:

Why does the following test fail and what can I do about it?

import { Component, ViewChild } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule, NgForm } from '@angular/forms';

@Component({
    selector: 'test-input',
    template: `<input name="inComponent" ngModel="dummy" required>`
})
class TestInputComponent {
}

@Component({
    template: `<form><input name="inForm" ngModel="dummy"><test-input></test-input></form>`
})
class TestFormComponent {
    @ViewChild(NgForm)
    form: NgForm;
}

fdescribe('Input in Form', () => {
    let component: TestFormComponent;
    let fixture: ComponentFixture<TestFormComponent>;

    beforeEach(async (() => {
        TestBed.configureTestingModule({
            declarations: [TestFormComponent, TestInputComponent],
            imports: [FormsModule]
        })
            .compileComponents();
    }));

    beforeEach(async () => {
        fixture = TestBed.createComponent(TestFormComponent);
        component = fixture.componentInstance;
        await fixture.whenStable();
        fixture.detectChanges();
    });

    it('form has all inputs', () => {
        expect(Object.keys(component.form.controls).sort()).toEqual(['inComponent', 'inForm']);
    });
});

Solution

  • Use viewProviders on your TestInputComponent, so it tells angular that you want this component to use existing NgForm

    @Component({
      selector: 'test-input',
      template: `<input name="inComponent" ngModel="dummy" required>`,
      viewProviders: [ { provide: ControlContainer, useExisting: NgForm }]
    })
    export class TestInputComponent implements OnInit {}
    

    Stackblitz: https://stackblitz.com/edit/angular-testing-kgwsca