David
David

Reputation: 133

Angular 2 event catching between sibling components

I've just begun learning Angular 2, and this is my first ever Stack Overflow question, so here goes...

I have an outer component with two nested inner components. I have a button in InnerComponent1 that, when clicked, fires an event that the outer component catches, which then passes the value (always true) into InnerComponent2. InnerComponent2 is displayed (*ngIf) based on that value.

It works.

Buuuut.. InnerComponent2 has a button that, when clicked, makes that value false, which hides the component.

That works too.

But once I've hidden InnerComponent2, the button in InnerComponent1 that displays InnerComponent2 no longer works. I'm not seeing any errors and I have confirmed that the outer component is still receiving the events.

Here's a plnkr that shows the scenario: http://plnkr.co/edit/X5YnNVm0dpFwA4ddv4u7?p=preview

Any thoughts?

Thanks very much.

Outer component

//our root app component
import {Component} from 'angular2/core';
import {Inner1Component} from 'src/inner1';
import {Inner2Component} from 'src/inner2';

@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <p>OuterComponent</p>
    <inner1 (show2)="show2Clicked = $event"></inner1>
    <inner2 [showMe]="show2Clicked"></inner2>
  `,
  directives: [Inner1Component, Inner2Component]
})
export class App {
  show2Clicked: boolean;
}

InnerComponent1

import {Component, EventEmitter, Output} from 'angular2/core'

@Component({
  selector: 'inner1',
  providers: [],
  template: `
    <p>inner1</p>
    <button (click)="showInner2()">Show inner2</button>
  `,
  directives: []
})
export class Inner1Component {
  @Output() show2 = new EventEmitter<boolean>();

  showInner2() {
    this.show2.emit(true);
  }
}

InnerComponent2

import {Component, Input} from 'angular2/core'

@Component({
  selector: 'inner2',
  providers: [],
  template: `
    <div *ngIf="showMe">
      <p>Inner2</p>
      <button (click)="showMe = false">Cancel</button>
    </div>
  `,
  directives: []
})
export class Inner2Component {
  @Input() showMe: boolean;
}

Upvotes: 12

Views: 11820

Answers (2)

Adel Sanhaji
Adel Sanhaji

Reputation: 11

I had the same problem, switching a form upon clicking a button from sibling component. My solution was to use a common service.

so in component 1 :

<button (click)="showMessageForm()" >
showForm = true;
showMessageForm() {
    this.messageService.switchMessageForm(this.showForm);
    this.showForm = !this.showForm;
}

in service :

switchMessageFormEvent = new EventEmitter<boolean>();
switchMessageForm(bSwitch:boolean) {
    this.switchMessageFormEvent.emit(bSwitch);
}

in component 2 :

ngOnInit() {
    this.messageService.switchMessageFormEvent.subscribe(
        (bSwitch: boolean) => {
            if(bSwitch) {
                $('.message-input').slideDown("normal");
            }else {
                this.myForm.reset();
                $('.message-input').slideUp("normal");
            }
        }
    );
}

Upvotes: 1

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

Reputation: 657288

The showMe and shwo2Clicked values get out of sync.

I added and EventEmitter to <inner2> and changed

<inner2 [showMe]="show2Clicked"></inner2>

to

<inner2 [(showMe)]="show2Clicked"></inner2>

I guess it's now working as you expect

http://plnkr.co/edit/tXzr3XgTrgMWMVzAw8d7?p=preview

update

The binding [showMe] works only in one direction. When show2Clicked is set to true, showMe will be set to true as well. Cancel sets showMe back to false. If then show2Clicked is set to true again, nothing happens because it is already true and showMe isn't updated. With the EventEmitter and two-way shorthand binding [(showMe)], show2Clicked is also set to false when showMe is set to false and setting it to true is actually a change that is propagated down though the binding.

[(showMe)]="show2Clicked" is a shorthand for [showMe]="show2Clicked" (showMeChange)="show2Clicked=$event" and the shorthand only works when the output has the same name as the input but with an additional Change

Upvotes: 10

Related Questions