Search code examples
angularangular2-directivesangular2-forms

Angular2: Parent and Child Components Communication


I'm trying to create a parent and child component where the child component is going to have a states drop down. Can someone help me understand how I can access the states drop down value in Parent Component? Here is my sample code.

/app/app.ts

import {Component} from 'angular2/core'
import {FORM_DIRECTIVES, FormBuilder, ControlGroup, Validators} from 'angular2/common'
import {State} from './state'

@Component({
  selector: 'my-app',
  providers: [FormBuilder],
  templateUrl: 'app/app.html',
  directives: [State]
})

export class App {
  registrationForm: ControlGroup;

  state: State;

  constructor(fb: FormBuilder) {

    this.registrationForm = fb.group({
      'name': ['', Validators.required],
      'email': ''
    });
  }

  onSubmit() {
    alert('Entered Name: ' + this.registrationForm.value.name);
    alert('State Selected: '); //trying to alert the state selected in state component
  }
}

/app/app.html

<div>
  <h2>Registration Form</h2>
  <form [ngFormModel]=registrationForm (ngSubmit)="onSubmit()">
    <label>Name: </label>
    <input type="text" ngControl="name">
    <state></state>
    <button [disabled]="!registrationForm.valid">Submit</button>
  </form>
</div>

/app/state.ts
import {Component} from 'angular2/core'
import {FORM_DIRECTIVES, FormBuilder, ControlGroup} from 'angular2/common'

@Component({
  selector: 'state',
  providers: [FormBuilder],
  templateUrl: 'app/state.html',
  directives: []
})

export class State {

  statesDropDownValues = ['NJ', 'NY', 'PA', 'CA'];

  stateForm: ControlGroup

  constructor(fb: FormBuilder) {
    this.stateForm = fb.group({
      'state': ''
    });

  }

  setStateValue() {
    alert('State Selected: ' + this.stateForm.value.state);
  }
}

/app/state.html
<div>
  <form [ngFormModel]="stateForm">
    <label>State: </label>
    <select ngControl="state" (change)="setStateValue()">
      <option *ngFor="#s of statesDropDownValues"
          [value]="s">{{s}}
      </option>
    </select>
  </form>
</div>

Also plunker here http://plnkr.co/edit/8tsm9sYeH8d8ulfqQKxY?p=info


Solution

  • I would define an output into your State component and triggers an event using it:

    @Component({
      selector: 'state',
      providers: [FormBuilder],
      templateUrl: 'app/state.html',
      directives: []
    })
    export class State {
      statesDropDownValues = ['NJ', 'NY', 'PA', 'CA'];
      stateForm: ControlGroup;
      @Output()
      stateChange:EventEmitter<string> = new EventEmitter(); // <----
    
      constructor(fb: FormBuilder) {
        this.stateForm = fb.group({
          'state': ''
        });
      }
    
      setStateValue() {
        alert('State Selected: ' + this.stateForm.value.state);
        stateChange.emit(this.stateForm.value.state);
      }
    }
    

    The parent component can register on this event to be notified of changes:

    <div>
      <h2>Registration Form</h2>
      <form [ngFormModel]=registrationForm (ngSubmit)="onSubmit()">
        <label>Name: </label>
        <input type="text" ngControl="name">
        <state (stateChange)="handleNewState($event)"></state>
        <button [disabled]="!registrationForm.valid">Submit</button>
      </form>
    </div>
    

    $event contains the value of the new state value.

    Edit

    Here is a way to save the selected state in the parent component:

    export class App {
      registrationForm: ControlGroup;
    
      state: string;
    
      constructor(fb: FormBuilder) {
        this.registrationForm = fb.group({
          'name': ['', Validators.required],
          'email': ''
        });
      }
    
      handleNewState(state) {
        this.state = state;
      }
    
      onSubmit() {
        alert('Entered Name: ' + this.registrationForm.value.name);
        alert('State Selected: ' + this.state);
      }
    }