17

I am adding form input fields using component -

engine-add-contact-form.html

<form (ngSubmit)="onSubmit()" [formGroup]="contact_form">
<md-tab-group>
    <md-tab label="Form">
        <ang-form></ang-form>
    </md-tab>
    <md-tab label="Email">
        <ang-email></ang-email>
    </md-tab>
    <md-tab label="Message">
        <ang-message></ang-message>
    </md-tab>
</md-tab-group>
<button md-raised-button type="submit">Publish</button>

ang-form.html

<div class="form-grid form-title">
     <md-input-container>
         <input formControlName="contact_form_title" 
        class="form-title-field" mdInput placeholder="Title" value="">
     </md-input-container>
</div>

Using same way i added other components (ang-email ang-message) html.

I added [formGroup] directive at engine-add-form.ts

export class EngineAddFormComponent{

contact_form: any;

form_value: any;

constructor(){
    this.contact_form = new FormGroup({
        contact_form_title: new FormControl('', Validators.minLength(2)),
        ........
        ........
    });
}
onSubmit(){
    this.form_value = JSON.stringify(this.contact_form.value);
    console.log(this.form_value);
}
}

I get following error -

Error: formControlName must be used with a parent formGroup directive. You'll want to add a formGroup directive and pass it an existing FormGroup instance (you can create one in your class).

I can't understand what is wrong with my code.

user3384985
  • 2,975
  • 6
  • 26
  • 42
  • You need to have `formGroup` directive within `ang-form.html` or use `formControl` directive instead of `formControlName` – yurzui Sep 27 '17 at 15:36
  • Here `ang-form` is a child component. But my `formGroup` directive is within parent component. So i think `formControl` directive would be my solution. Can you please give any working documentation for `formControl` directive? – user3384985 Sep 27 '17 at 15:40

4 Answers4

30

You need to pass formGroup (in your case contact_form) to child component which is ang-form

engine-add-contact-form.html(modified)

<form (ngSubmit)="onSubmit()" [formGroup]="contact_form">
<md-tab-group>
    <md-tab label="Form">
        <ang-form [group]="contact_form"></ang-form>
    </md-tab>
    <md-tab label="Email">
        <ang-email></ang-email>``
    </md-tab>
    <md-tab label="Message">
        <ang-message></ang-message>
    </md-tab>
</md-tab-group>
<button md-raised-button type="submit">Publish</button>

ang-form.html(modified)

<div class="form-grid form-title" [formGroup]="group">
     <md-input-container>
         <input formControlName="contact_form_title" 
        class="form-title-field" mdInput placeholder="Title" value="">
     </md-input-container>
</div>

Add @Input() group: FormGroup; in your ang-form.component.ts

Rahul Kumar
  • 5,120
  • 5
  • 33
  • 44
Abhishek Singh
  • 1,631
  • 1
  • 17
  • 31
  • 2
    While this works it can screw up .submitted state for the form because the `submit` event isn't triggered on the formGroup instance. Note that `FormGroup` and `FormGroupDirective` are different things, and a new 'directive' is created even though you're reusing the formGroup data model. – Simon_Weaver Jan 04 '19 at 00:53
21

There are a lot of options of doing this.

1) Here is an example that uses formControl directive and angular DI system:

@Component({
  selector: 'ang-form',
  template: `
    <input [formControl]="control">
  `
})
export class AngForm {
  control: FormControl;

  constructor(private formGroupDir: FormGroupDirective) {}

  ngOnInit() {
    this.control = this.formGroupDir.control.get('contact_form_title') as FormControl;
  }
}

Stackblitz Example

2) Another way it to define ControlContainer view provider on child component:

@Component({
  selector: 'ang-form',
  template: `
     <input formControlName="contact_form_title">
    `,
  viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }]
})
export class AngForm { }

Stackblitz Example

For more examples see:

yurzui
  • 205,937
  • 32
  • 433
  • 399
  • 1
    This solution does not have the problem that Abhiskek's answer does, whereby `issubmitted` is not set for the formgroup. This solution does not have that problem because it is reusing the same directive that was originally defined on the form. – Simon_Weaver Jan 04 '19 at 01:46
  • 2
    @Simon_Weaver Check also another way https://stackblitz.com/edit/angular-ku6lt7?file=app/ang-form.component.ts – yurzui Jan 04 '19 at 05:47
0

Wrap the input in a div and pass the formGroup into the div:

<div [formGroup]="formGroup">
  <input ...>
</div>
James L.
  • 12,893
  • 4
  • 49
  • 60
0
<form [formGroup]="guestForm" novalidate>
    <div class="panel-body">
        <form> -> Remove this
            <div class="col-md-12 col-sm-12">
                <div class="form-group col-md-3 col-sm-6">
                    <label>First Name*  </label>
                    <input formControlName="firstname" type="text" class="form-control input-sm">
                </div>
            </div>
        </form> -> Remove this
    </div>
</form>