Passing data between parent and child components
angular really does carry subscriber-receiver all the way through, and that includes child-to-parent, which also runs on the Observable mechanism, the child publishes an event, the parent subscribes to that event and waits for it to fire before running the matching callback.
Take the operation below, the child sets up an Output and publishes an event outward. this.commit.emit(val) is the part that fires the event, sending the subscriber the signal that a callback needs to run, and val is what $event passes back, defined with <T> at the time you new it.
@Component({ selector: 'app-child', ... })
export class ChildComponent {
@Input() value = ''; // takes in the parent's state
@Output() commit = new EventEmitter<string>(); // defines the callback exit
onInput(event: Event) {
const val = (event.target as HTMLInputElement).value;
this.commit.emit(val); // fire the callback, pass the new value up to the parent
}
}
The parent below uses [v] to set the child’s Input, and () subscribes to the event the child publishes, whose content is of course the callback for when that event fires.
<app-child
[value]="form.get('username')?.value"
(commit)="form.get('username')?.setValue($event)">
</app-child>
The Output here only needs to be an Observable, there’s no hard requirement to use EventEmitter, but that isn’t the recommended way. Since the official guidance already says to go with events, sticking to the standard is the best way to keep the unexpected from showing up. You could say that finding some inexplicable custom Observable in this spot is a code smell. Unless there really is some extreme case that forces you to define your own, you shouldn’t be using it under normal circumstances.
Translation note. I wrote this in Chinese. This English version is an LLM translation, so the wording is not mine even though the thinking is. Original: 父子組件傳參.