Angular 2 event catching between sibling components

11,150

Solution 1

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

Solution 2

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");
            }
        }
    );
}
Share:
11,150

Related videos on Youtube

David
Author by

David

Updated on September 14, 2022

Comments

  • David
    David over 1 year

    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;
    }
    
  • David
    David about 8 years
    Perfect. Thanks very much for your speedy response. Works as expected. Just to clarify exactly what is going here: We need the event emitter in inner2 just to trigger the re-evaluation of the variables and the rerender? Because the showMeChange event that is emitted isn't captured anywhere.
  • David
    David about 8 years
    Shorthand. Gotcha. That's exactly what I was looking for. Thanks very much. The official Angular2 documentation is still lacking, understandably.
  • user2180794
    user2180794 over 7 years
    this thing is critical for it to work shorthand only works when the output has the same name as the input but with an additional Change And you are awesome @Günter Zöchbauer
  • Günter Zöchbauer
    Günter Zöchbauer over 7 years