Repository navigation
Implement @ObserveChildren or similar API #5467
Description
Previously discussed with @vsavkin and @jeffbcross
Background - programmatically listening to events propagated by children is difficult currently.
Consider:
You have a <accordion> component and n <accordion-item> components:
<accordion>
<accordion-item></accordion-item>
<accordion-item></accordion-item>
<accordion-item></accordion-item>
</accordion>
An accordion-item component might emit a select event/output, used to set it as the currently active item.
Currently the best way to achieve this is the accordion-item component would inject the parent accordion, and have the accordion-item register itself with the parent, and call a method to close the others
@Component({selector: 'accordion' })
class Accordion {
_items: []AccordionItem = [];
register(item: AccordionItem){
this._items.push(item);
}
toggleActive(selectedItem:AccordionItem){
this._items.forEach(item => {
if(item !== selectedItem){
item.active = false;
}
});
selectedItem.active = true;
}
}
@Component({selector: 'accordion-item' , inputs: ['active'] })
class AccordionItem {
active: boolean;
constructor(private accordion: Accordion){
accordion.register(this);
}
setActive(){
this.accordion.toggleActive(this);
}
}Ideally, a child component would simply expose a 'select' event:
@Component({selector: 'accordion-item' })
class AccordionItem {
@Input() active: boolean;
@Output selected:EventEmitter<AccordionItem> = new EventEmitter();
active: boolean;
setActive(){
this.selected.emit(this);
}
}The parent accordion can currently easily get ahold of the children via @ViewChildren() (or whatever) but there is a not a clean way to listen to events emitted from the children.
Proposed Syntax:
Implement a @ObserveChildren decorator (or similar) that would enable Observation of events emitted by child components:
@Component({selector: 'accordion' })
class Accordion {
//specify type and desired output to Observe.
@ObserveChildren(AccordionItem, 'select') childSelections: Observable<AccordionItem>
@ViewChildren(AccordionItem) children: Observable<AccordionItem>
afterViewInit(){
this.updates = Observable
.combineLatest(this.children, this.childSelections, (children, selected) => ({children, selected}))
.do(({children, selected) => children.map(child => { //update state }))
.subscribe();
}
onDestroy(){
this.updates.unsubscribe();
}
}
Activity
Foxandxss commentedon Nov 25, 2015
This idea is awesome.
The problem with the current pattern is that it lacks functionality.
With
QueryListyou can say: Hey give me all my children. That is nice, that simplifies a lot of patterns like accordion, carousel or tabs.The problem with the
QueryListis that it is a bit useless by itself. You have access to first item, last item, all items or subscribe to get add / removal of children. Useful stuff, but ... no way of doing concrete stuff with children.In angular 1, children requires the parent and in collaboration with the parent, you couple both together to do stuff.
In angular 2, the idea idea is to move the responsibility to the parent so the children is more of a dumb component that outputs its changes.
I really like this idea, but currently as @robwormald pointed out, the paren't can't take any responsibility because they don't know what their children do. We need a way to observe those children, listen to what we need from them so we can trigger the needed logic. That way we have simple components and reusable children.
fenduru commentedon May 7, 2016
I work on a UI library for the rest of my company, so I am also very interested in patterns like this.
I completely agree with @Foxandxss that it is really easy to access the children but not easy to do anything concrete with them. For components that I have worked on in Angular 1, the kinds of things I have wanted to do with the child components fall into one of three categories:
For something like a
<checklist>that contains<checkbox>s, then the categories above become:<checkbox>s<checklist>'s output based on the output of the<checkbox>s<checkbox>in an extra DOM elementCase 1 theoretically works except the change detector complains (Should I file a bug for this?).
For case 2, I think a decorator that creates an Observable would work very nicely. Hopefully this feature would work with both
@ViewChildrenand@ContentChildrensince that could also close #4062I'm not sure if case 3 has been discussed at all, but this would basically be a more flexible method of content projection than
ng-content. I think it would be great if{{ someElementRef }}would stick the element there, though I'm sure there are some corner cases with that. This would allow a component like:(I know that example doesn't make complete sense because
childrenisQueryList<Child>notQueryList<ElementRef>, but that is the general idea I'm trying to get at).If these 3 concepts were supported, I would be in heaven because in Angular 1 I have always dreamed about shifting responsibility out of the child components.
P.S. thanks @IgorMinar for chatting with me at the end of ngConf and pointing me toward this issue
pkozlowski-opensource commentedon Jun 6, 2016
What is described here has many common points with #4062 and as such both issues could / should be considered together. Adding a comment to have cross-reference.
DzmitryShylovich commentedon Feb 4, 2017
@robwormald close in favor of #13248 ?
splincode commentedon Jul 26, 2018
@robwormald Is the issue relevant?
1 remaining item
ohabash commentedon Apr 29, 2020
will this solution help me with this problem? https://stackoverflow.com/questions/61513365/output-from-directive-will-print-in-parent-but-cannot-update-a-value-in-parent
thePunderWoman commentedon Oct 17, 2025
Closing since we now have
OutputRef, which has.subscribemaking this technically possible now.angular-automatic-lock-bot commentedon Nov 17, 2025
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.