4

I am building a page with several dynamic panels, each child panel has the same HTML so I have created a parent panel component to wrap each one.

The problem is I want to send an event from the child to the panel but I cant seem to find an answer. Here's what I have so far:

// Panel Panel Component
@Component({
    selector: 'panel',
    template: `
    <div (emittedEvent)="func($event)">
        <ng-content></ng-content>
    </div>
    `
})
export class PanelComponent {

    constructor() {}

    func(event) {
    // Do stuff with the event
    }
}
// Child Panel Component (one of many)
@Component({
selector: 'child-panel-one',
template: `
    // Template stuff
    <button (click)="emitEvent()">Click</button>
`
})
export class ChildPanelOne {
emittedValue: Boolean = false;

@Output() emittedEvent = new EventEmitter();

constructor() {}

private emitEvent() {
    this.emittedValue = true;

    this.emittedEvent.emit(this.emittedValue)
}
}
//
// Main Parent Template
<panel>
    <child-panel-one></child-panel-one>
</panel>

I could create a shared service but it seems an overkill for passing a boolean value from child to parent.

Any ideas?

Thanks

Vamshi
  • 9,194
  • 4
  • 38
  • 54
EJP
  • 181
  • 4
  • 13

2 Answers2

8

There are several ways

<panel #p>
    <child-panel-one (emittedEvent)="p.func($event)"></child-panel-one>
</panel>

but this requires the user of <panel> to set up the event binding

or you could a DOM event like shown in in Angular2 how to know when ANY form input field lost focus

or you could use ´@ContentChildren()` and then subscribe imperatively

@ContentChildren(ChildPanelOne) childPanels:QueryList<ChildPanelOne>
ngAfterContentInit() {
  this.childPanels.toArray().forEach(cp => cp.emittedValue.subscribe(() => ...));
}

but that requires all child panels to be of predefined types.

You could also use a shared service with an observable that child components inject and use to emit events to the parent component.

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    Thanks for your answer and the link too. The service seems the best way to go - that way the panel component doesn't need to need all child panels defined as you described above. I've created a very simple service scoped to the panel and its children which – EJP Apr 05 '17 at 12:35
  • 2
    For anyone else with a similar issue, this Plunkr demos the shared EmitterService http://plnkr.co/edit/Kt7jpEwzKC8ljvKGLbKt?p=preview – EJP Apr 05 '17 at 12:36
  • Thanks for your feedback. Glad to hear you could find a solution that works for you. I'd also use a service. – Günter Zöchbauer Apr 05 '17 at 12:37
  • 1
    You could also let all the content children inherit from a base-component with a generic output (e.g. onChange) and subscribe to that in your component with the in its template. – Kristofer Apr 09 '17 at 21:34
0

Another way to catch event from the content child is to take ref of parent comp and define

constructor(app:AppComponent){ //<-- get the ref of the parent component
    app['clic'] = this.clic; //<-- declare function and bind our function 
    this.name = 'myself';
}

clic(){
    alert('clicked');
}

ngOnDestroy() {
    delete this.app['clic']; // <-- get rid of the function from parent component, when we are done
}

WORKING DEMO ( CHECK THIS ALSO )

Vivek Doshi
  • 56,649
  • 12
  • 110
  • 122