Reputation: 34553
I have a custom modal component which uses <ng-content>
to transclude content:
@Component({
selector: 'modal-container',
template: `
<div [class]="css">
<div [attr.id]="id" class="reveal" (open)="openModal()">
<ng-content></ng-content>
</div>
</div>
`
})
export class ModalContainerComponent {
. . .
}
In the contents of <ng-content>
I have a component which emits the open
event:
@Component({
selector: 'login-modal',
template: `
<modal-container [id]="'login-modal'">
<section>...</section>
</modal-container>
`,
})
export class LoginModalComponent implements OnInit {
@Output()
open = new EventEmitter();
ngOnInit(): void {
// Here I am checking an ngrx store with code that is not included
if (state.openLoginModal) {
this.open.emit();
}
}
}
however, the ModalContainerComponent
never receives the event.
Examples such as:
are coming up short. What am I doing wrong?
Since @Output
events don't bubble, I decided to go with a custom directive to emit the event:
import { Directive, ElementRef, Renderer } from '@angular/core';
@Directive({
selector: '[open-modal]',
host: { '(click)': 'openModal()' }
})
export class OpenModalDirective {
constructor(
private elementRef: ElementRef,
private renderer: Renderer
) {}
openModal(): void {
this.renderer.invokeElementMethod(this.elementRef.nativeElement,
'dispatchEvent',
[new CustomEvent('open-modal-container', { bubbles: true })]);
}
}
using: in Angular2 how to know when ANY form input field lost focus as an example.
However, I still can't pick up the custom event in ModalContainerComponent
:
@HostListener('open-modal-container')
openModalContainer(): void {
console.log('openModal() was invoked');
}
I can log the click event, so that's happening, but the host listener is failing. Thoughts?
I'm abandoning this approach in favor of a shared service, but I'm running into an issue with .next()
not providing a value to the subscriber: Subscriber doesn't receive value from .next()
Upvotes: 12
Views: 18455
Reputation: 857
In my use case I find this work around
The custom component view contains ng-content
<!-- more code -->
<ng-template #matchCodeModal let-modal>
<div>
<ng-content></ng-content>
</div>
</ng-template>
<!-- more code -->
in the parent component I'm providing the ng-content with transclude content
<fw-match-code #match [(value)]="tc.filters.idSostanza" (enterPressed)="tc.refresh()">
<app-sostanze popup="true" (selected)="match.onSelect($event)"></app-sostanze>
</fw-match-code>
I needed to capture selected event emitted by app-sostanze component inside fw-match-code.
I managed to do that associating a template variable called #match to fw-match-code and the triggering match.onSelect($event) on the component behind the view:
export class MatchCodeComponent implements OnInit {
//...
onSelect(data: any): void {
this.modal?.dismiss(data);
}
//...
}
Upvotes: 0
Reputation: 3331
Just to expand on rob'a answer and comment
@ContentChild(LoginModalComponent) private models: QueryList<LoginModalComponent>;
ngAfterViewInit() {
let models = this.models.toArray();
for (let key in panels) {
let model = models[key];
panel.open.subscribe(()=>{
// do things
});
}
}
This works in my case, and included for completeness.
Upvotes: 1
Reputation: 34553
I ended up abandoning the event-driven approach and went with a shared service class instead.
Upvotes: 3
Reputation: 2077
Event emitters in Angular are not bubbling up. If you want an event that bubbling up, you should create an event with CustomEvent. In your case the event will work only if your register it on the component itself:
<login-modal (open)="func()"></login-modal>
Upvotes: 0
Reputation: 18513
You could get an instance of the login modal with @ContentChild()
and manually subscribe to the open event
@Component({
selector: 'modal-container',
template: `
<div [class]="css">
<div [attr.id]="id" class="reveal" (open)="openModal()">
<ng-content></ng-content>
</div>
</div>
`
})
export class ModalContainerComponent {
@ContentChild(LoginModalComponent)
loginModal: LoginModalComponent;
ngAfterViewInit() {
this.loginModal.open.subscribe((event) => {
//Handel event here
});
}
}
Upvotes: 7