Reputation: 23
I'm an experienced programmer but pretty new to Angular.
I've just gone through a good Angular tutorial and tried out to practice passing values from a child component to its caller (parent).
Somehow, eventhough I reduce the complexity to minimum, my parent function is not even called, which I've bound to the emitter.
After serving the application (ng serve), I see only the following in the console:
child.component.ts:17 submitButtonClicked called
I stepped into the emit-Call using the VS Code and Debugger for Chrome:
submitButtonClicked() {
console.log("submitButtonClicked called");
this.emitter.emit("Test");
}
After two steps, I landed in the Subject.js and saw, that its member variable "observers" is empty. I would expect, that the observers array contain at least the ParentComponent. See the Subject.js code snipped at the end of the page.
I mean, it's really simple but I just can't identify, where I've the mistake :-/
What could be the cause and the solution?
I really would appreciate your help!
Parent (parent.component.html)
<p>parent works!</p>
<app-child (submitButtonClicked)="parentFunction($event)"></app-child>
Parent (parent.component.ts)
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
parentFunction (str: string) {
console.log("parentFunction called, str = " + str);
}
}
Child (child.component.html)
<p>child works!</p>
<button type="submit" (click)="submitButtonClicked()">Submit</button>
Child (child.component.ts)
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {
@Output() emitter = new EventEmitter<string>();
constructor() { }
ngOnInit(): void {
}
submitButtonClicked() {
console.log("submitButtonClicked called");
this.emitter.emit("Test");
}
}
Root (app.component.html)
<app-parent></app-parent>
Root (app.component.ts)
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'My App';
}
Root Module (app.module.ts)
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { ParentComponent } from './parent/parent.component';
import { ChildComponent } from './child/child.component';
@NgModule({
declarations: [
AppComponent,
ParentComponent,
ChildComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Subject.js
export class Subject extends Observable {
constructor() {
super();
this.observers = [];
this.closed = false;
this.isStopped = false;
this.hasError = false;
this.thrownError = null;
}
[rxSubscriberSymbol]() {
return new SubjectSubscriber(this);
}
lift(operator) {
const subject = new AnonymousSubject(this, this);
subject.operator = operator;
return subject;
}
next(value) {
if (this.closed) {
throw new ObjectUnsubscribedError();
}
if (!this.isStopped) {
const { observers } = this;
const len = observers.length;
const copy = observers.slice();
for (let i = 0; i < len; i++) {
copy[i].next(value);
}
}
}
... // Snippet ends here
My Angular environment (ng --version):
Angular CLI: 9.0.7
Node: 12.16.1
OS: win32 x64
Angular: 9.0.7
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes
Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.900.7
@angular-devkit/build-angular 0.900.7
@angular-devkit/build-optimizer 0.900.7
@angular-devkit/build-webpack 0.900.7
@angular-devkit/core 9.0.7
@angular-devkit/schematics 9.0.7
@ngtools/webpack 9.0.7
@schematics/angular 9.0.7
@schematics/update 0.900.7
rxjs 6.5.5
typescript 3.7.5
webpack 4.41.2
Upvotes: 1
Views: 2350
Reputation: 31145
You don't have to dig deep down. It's a simple fix. The emitter is called emitter
. So you have to bind to that name. Try the following
<app-child (emitter)="parentFunction($event)"></app-child>
Or if you wish to bind to submitButtonClicked
, then the emitter should be called submitButtonClicked
.
@Output() submitButtonClicked = new EventEmitter<string>();
If you wish to learn more about event emitter, you could look at it's source. It is a simple extension of a Rxjs Subject. So when an event emitter is created, it actually is an observable called by the name decorated with the @Output()
decorator. So to obtain the values from the emitter, it needs to be subscribed to. And the emitter name is the name of the observable that is being subscribed to.
Upvotes: 0