Fran b
Fran b

Reputation: 3036

Angular2 Reference between components

I'm learning Angular 2, about injection dependencies and providers but I have a doubt. My app has 2 components: TrainingComponent and ExerciseFormComponent. The idea is 1 Training has N Exercises. The Training component has an attribute Exercises which holds an array of exercises and ExerciseFormComponent has a method: submit() which is invoked when a new exercise is created. Next I want submit() add the new exercise to TrainingComponent using addExerecise(exercise: Exercise) but I don't know how to pass it reference to be able to invoke it.

ExerciseFormComponent

import {Component} from 'angular2/core';
import {NgForm}    from 'angular2/common';
import {Exercise}  from './exercise';
import {TrainingComponent}  from './training.component';

@Component({
  selector: 'exercise-form',
  templateUrl: 'app/exercise-form.component.html',
  directives: [TrainingComponent]
})

export class ExerciseFormComponent {
    model = new Exercise(6, 'hola', 10, 'hey', 11, 12);
    active = true;
    submitted = false;

    constructor(private _trainingComponent: TrainingComponent) {}

    onSubmit() { 
      this.submitted = true;
      //This doesn't work!
      this._trainingComponent.addExercise(this.model); 
    }

    newExercise() {
        this.model = new Exercise(7, '', 0, '', 0, 0);
        this.active = false;
        setTimeout(()=> this.active=true, 0);
    }

    // TODO: Remove this when we're done
    get diagnostic() { return JSON.stringify(this.model); }
}

TrainingComponent

import {Component} from 'angular2/core';
import {Exercise} from './exercise';
import {ExerciseFormComponent} from './exercise-form.component';
import {ExerciseService} from './exercise.service';

@Component({
  selector: 'app',
  template:`
    <h1>{{title}}</h1>
    <h2>My Training</h2>
    <button type="button" (click)="getExercises()">Shoot!</button>
    <ul class="training">
      <li *ngFor="#exercise of exercises">
        <span class="badge">{{exercise.id}}</span> {{exercise.name}}
      </li>
    </ul>
    <exercise-form></exercise-form>
  `,
  directives: [ExerciseFormComponent],
  providers: [ExerciseService]
})    

export class TrainingComponent {
  public title = 'Training';
  public exercises: Exercise[];
  constructor(private _exerciseService: ExerciseService) { }
  getExercises() {
    this._exerciseService.getExercises().then(exercises => this.exercises = exercises);
  }

  // This method is who should be invoked from submit() in ExerciseFormComponent
  addExercise(exercise: Exercise){
    this.exercises.push(exercise);
  }
}

Upvotes: 2

Views: 204

Answers (1)

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 658067

It's better to use binding with inputs and outputs than creating tight coupling between components.

This way you can produce an event (using @Output())

export class ExerciseFormComponent {
   @Output() exerciseAdded:EventEmitter<Exercise> = new EventEmitter<Exercise>();

   onSubmit() { 
      this.submitted = true;
      //This doesn't work!
      this.exerciseAdded.emit(this.model); 
    }

this way you can subscribe to the event and call a method when an event occurs:

<exercise-form (exerciseAdded)="addExercise($event)"></exercise-form>

Upvotes: 2

Related Questions