ThreeAccents
ThreeAccents

Reputation: 1882

Sending action to parent component Angular2

I have 2 components one is a Topbar and the second is a Display here they are:

Display:

import {Component, View, NgIf} from 'angular2/angular2';

import {Topbar} from '../topbar/topbar';

@Component({
  selector: 'display'
})
@View({
  templateUrl: './components/display/display.html',
  styleUrls: ['./components/display/display.css'],
  directives: [Topbar, NgIf]
})

export class Display {
    showGrid: boolean;

    constructor(){
        this.showGrid = true;
    }
}

Display HTML(important for my issue):

<topbar></topbar>
<div *ng-if="showGrid" class="display-list">
    <h1>true</h1>
</div>
<div *ng-if="showGrid == false" class="display-list">
    <h1>false</h1>
</div>

As you can see I have an if statement depending on the showGrid property. Now here is my Topbar component:

Topbar:

import {Component, View} from 'angular2/angular2';
import {ROUTER_DIRECTIVES} from 'angular2/router';

@Component({
  selector: 'topbar'
})
@View({
  templateUrl: './components/topbar/topbar.html',
  styleUrls: ['./components/topbar/topbar.css'],
  directives: [ROUTER_DIRECTIVES]
})
export class Topbar {
  toggleGrid(){
    // update Display showGrid property
  }
}

Topbar HTML:

<div (click)="toggleGrid()" class="col-md-1 no-padding grid-toggle">
  <img src="assets/imgs/icons/icon-list.svg">
</div>

As you can see I have a function toggleGrid this function is to toggle the Display property showGrid; however, I can't seem to find a way to get this done. Since Topbar is a directive of Display I can't inject Display into Topbar. I've tried creating a service but the issue with this is that it doesn't update the Display showGrid property

Upvotes: 3

Views: 4901

Answers (1)

alexpods
alexpods

Reputation: 48535

There is two approaches:

1.

You just need to define some toggle-grid event (output property) for your <toolbar> component and then listen to it in your Display component. See this plunker.

@Component({
  selector: 'topbar'
})
@View({
  template: `
    <div (click)="onButtonClick()">
      Button
    </div>
  `
})
export class Topbar {
  @Output() toggleGrid = new EventEmitter();

  onButtonClick() {
    this.toggleGrid.next();
  }
}

@Component({
  selector: 'display'
})
@View({
  directives: [Topbar, NgIf],
  template: `
    <topbar (toggle-grid)="toggleGrid()"></topbar>
    <div *ng-if="showGrid" class="display-list">
        <h1>true</h1>
    </div>
    <div *ng-if="showGrid == false" class="display-list">
        <h1>false</h1>
    </div>
  `
})
export class Display {
    showGrid: boolean = true;

    toggleGrid() {
      this.showGrid = !this.showGrid;
    }
}

2.

Use @Host and maybe forwardRef to inject parent component into child. See this plunker

@Component({
  selector: 'topbar'
})
@View({
  template: `
    <div (click)="onButtonClick()">
      Button
    </div>
  `
})
export class Topbar {
  display: Display;

  constructor(@Host() @Inject(forwardRef(() => Display)) display: Display) {
    this.display = display;
  }

  onButtonClick() {
    this.display.toggleGrid()
  }
}

@Component({
  selector: 'display'
})
@View({
  directives: [Topbar, NgIf],
  template: `
    <topbar></topbar>
    <div *ng-if="showGrid" class="display-list">
        <h1>true</h1>
    </div>
    <div *ng-if="showGrid == false" class="display-list">
        <h1>false</h1>
    </div>
  `
})
export class Display {
    showGrid: boolean = true;

    toggleGrid() {
      this.showGrid = !this.showGrid;
    }
}

Personally, I much prefer the first approach as it makes data flow of your application to be more explicit.

Upvotes: 8

Related Questions