<p dir="auto">App Component template</p>
<div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&lt;tabs&gt;
  &lt;tab-link&gt;Chat notification component goes here&lt;/tab-link&gt;
  &lt;tab&gt;Chat display component goes in here&lt;/tab&gt;

 &lt;tab-link&gt;Other Chat notification component goes here&lt;/tab-link&gt;
  &lt;tab&gt;Other Chat display component goes in here&lt;/tab&gt;
&lt;/tabs&gt;"><pre class="notranslate"><span class="pl-kos">&lt;</span><span class="pl-ent">tabs</span><span class="pl-kos">&gt;</span>
  <span class="pl-kos">&lt;</span><span class="pl-ent">tab-link</span><span class="pl-kos">&gt;</span>Chat notification component goes here<span class="pl-kos">&lt;/</span><span class="pl-ent">tab-link</span><span class="pl-kos">&gt;</span>
  <span class="pl-kos">&lt;</span><span class="pl-ent">tab</span><span class="pl-kos">&gt;</span>Chat display component goes in here<span class="pl-kos">&lt;/</span><span class="pl-ent">tab</span><span class="pl-kos">&gt;</span>

 <span class="pl-kos">&lt;</span><span class="pl-ent">tab-link</span><span class="pl-kos">&gt;</span>Other Chat notification component goes here<span class="pl-kos">&lt;/</span><span class="pl-ent">tab-link</span><span class="pl-kos">&gt;</span>
  <span class="pl-kos">&lt;</span><span class="pl-ent">tab</span><span class="pl-kos">&gt;</span>Other Chat display component goes in here<span class="pl-kos">&lt;/</span><span class="pl-ent">tab</span><span class="pl-kos">&gt;</span>
<span class="pl-kos">&lt;/</span><span class="pl-ent">tabs</span><span class="pl-kos">&gt;</span></pre></div>
<p dir="auto">Tabs Component template</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="&lt;div (tabSwitch)=&quot;setActiveTab($event.target)&quot; class=&quot;navigation&quot;&gt;
  &lt;ng-content select=&quot;tab-link&quot;&gt;&lt;/ng-content&gt;
&lt;/div&gt;
&lt;ng-content select=&quot;tab&quot;&gt;&lt;/ng-content&gt;"><pre class="notranslate"><code class="notranslate">&lt;div (tabSwitch)="setActiveTab($event.target)" class="navigation"&gt;
  &lt;ng-content select="tab-link"&gt;&lt;/ng-content&gt;
&lt;/div&gt;
&lt;ng-content select="tab"&gt;&lt;/ng-content&gt;
</code></pre></div>
<p dir="auto">UPDATE: This is the tab-link template(I forgot to put it in the first post)</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="&lt;a (click)=&quot;select()&quot; [class.active]=&quot;active&quot;&gt;
 &lt;ng-content&gt;&lt;/ng-content&gt;
&lt;/a&gt;"><pre class="notranslate"><code class="notranslate">&lt;a (click)="select()" [class.active]="active"&gt;
 &lt;ng-content&gt;&lt;/ng-content&gt;
&lt;/a&gt;
</code></pre></div>
<p dir="auto">Tab-Link Component ts</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="export class TabLink {
  @Output('tabSwitch') tabSelected: EventEmitter&lt;TabLink&gt; = new EventEmitter();

  select(){
    this.tabSelected.emit(this);
    console.log('click tab link');
  }
}"><pre class="notranslate"><span class="pl-k">export</span> <span class="pl-k">class</span> <span class="pl-smi">TabLink</span> <span class="pl-kos">{</span>
  @<span class="pl-smi">Output</span><span class="pl-kos">(</span><span class="pl-s">'tabSwitch'</span><span class="pl-kos">)</span> <span class="pl-c1">tabSelected</span>: <span class="pl-smi">EventEmitter</span><span class="pl-kos">&lt;</span><span class="pl-smi">TabLink</span><span class="pl-kos">&gt;</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-smi">EventEmitter</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

  <span class="pl-en">select</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">{</span>
    <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">tabSelected</span><span class="pl-kos">.</span><span class="pl-en">emit</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'click tab link'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">Tabs Component ts</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="export class Tabs {
  setActiveTab(link: TabLink):void{
   console.log(&quot;hello&quot;, TabLink);
  }
}"><pre class="notranslate"><span class="pl-k">export</span> <span class="pl-k">class</span> <span class="pl-smi">Tabs</span> <span class="pl-kos">{</span>
  <span class="pl-en">setActiveTab</span><span class="pl-kos">(</span><span class="pl-s1">link</span>: <span class="pl-smi">TabLink</span><span class="pl-kos">)</span>:<span class="pl-smi"><span class="pl-k">void</span></span><span class="pl-kos">{</span>
   <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">"hello"</span><span class="pl-kos">,</span> <span class="pl-smi">TabLink</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">I would expect the setActiveTab method to fire when I click the TabLink, but nothing.<br>
I have tried moving the <code class="notranslate">tabSwitch</code> event listener around, but nothing works.</p>
<p dir="auto">Any thoughts?</p>
<p dir="auto">Previously discussed with <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/vsavkin/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/vsavkin">@vsavkin</a> and <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/jeffbcross/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/jeffbcross">@jeffbcross</a></p>
<p dir="auto">Background - programmatically listening to events propagated by children is difficult currently.</p>
<p dir="auto">Consider:<br>
You have a <code class="notranslate">&lt;accordion&gt;</code> component and n <code class="notranslate">&lt;accordion-item&gt;</code> components:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="&lt;accordion&gt;
  &lt;accordion-item&gt;&lt;/accordion-item&gt;
  &lt;accordion-item&gt;&lt;/accordion-item&gt;
  &lt;accordion-item&gt;&lt;/accordion-item&gt;
&lt;/accordion&gt;"><pre class="notranslate"><code class="notranslate">&lt;accordion&gt;
  &lt;accordion-item&gt;&lt;/accordion-item&gt;
  &lt;accordion-item&gt;&lt;/accordion-item&gt;
  &lt;accordion-item&gt;&lt;/accordion-item&gt;
&lt;/accordion&gt;
</code></pre></div>
<p dir="auto">An accordion-item component might emit a <code class="notranslate">select</code> event/output, used to set it as the currently active item.</p>
<p dir="auto">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</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="@Component({selector: 'accordion' })
class Accordion {
  _items: []AccordionItem = [];
  register(item: AccordionItem){
    this._items.push(item);
  }
  toggleActive(selectedItem:AccordionItem){
    this._items.forEach(item =&gt; {
      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);
  }
}"><pre class="notranslate">@<span class="pl-smi">Component</span><span class="pl-kos">(</span><span class="pl-kos">{</span><span class="pl-c1">selector</span>: <span class="pl-s">'accordion'</span> <span class="pl-kos">}</span><span class="pl-kos">)</span>
<span class="pl-k">class</span> <span class="pl-smi">Accordion</span> <span class="pl-kos">{</span>
  <span class="pl-c1">_items</span>: <span class="pl-kos">[</span><span class="pl-kos">]</span><span class="pl-smi">AccordionItem</span> <span class="pl-c1">=</span> <span class="pl-kos">[</span><span class="pl-kos">]</span><span class="pl-kos">;</span>
  <span class="pl-en">register</span><span class="pl-kos">(</span><span class="pl-s1">item</span>: <span class="pl-smi">AccordionItem</span><span class="pl-kos">)</span><span class="pl-kos">{</span>
    <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">_items</span><span class="pl-kos">.</span><span class="pl-en">push</span><span class="pl-kos">(</span><span class="pl-s1">item</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
  <span class="pl-en">toggleActive</span><span class="pl-kos">(</span><span class="pl-s1">selectedItem</span>:<span class="pl-smi">AccordionItem</span><span class="pl-kos">)</span><span class="pl-kos">{</span>
    <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">_items</span><span class="pl-kos">.</span><span class="pl-en">forEach</span><span class="pl-kos">(</span><span class="pl-s1">item</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
      <span class="pl-k">if</span><span class="pl-kos">(</span><span class="pl-s1">item</span> <span class="pl-c1">!==</span> <span class="pl-s1">selectedItem</span><span class="pl-kos">)</span><span class="pl-kos">{</span>
        <span class="pl-s1">item</span><span class="pl-kos">.</span><span class="pl-c1">active</span> <span class="pl-c1">=</span> <span class="pl-c1">false</span><span class="pl-kos">;</span>
      <span class="pl-kos">}</span>
    <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-s1">selectedItem</span><span class="pl-kos">.</span><span class="pl-c1">active</span> <span class="pl-c1">=</span> <span class="pl-c1">true</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span>

@<span class="pl-smi">Component</span><span class="pl-kos">(</span><span class="pl-kos">{</span><span class="pl-c1">selector</span>: <span class="pl-s">'accordion-item'</span> <span class="pl-kos">,</span> <span class="pl-c1">inputs</span>: <span class="pl-kos">[</span><span class="pl-s">'active'</span><span class="pl-kos">]</span> <span class="pl-kos">}</span><span class="pl-kos">)</span>
<span class="pl-k">class</span> <span class="pl-smi">AccordionItem</span> <span class="pl-kos">{</span>
  <span class="pl-c1">active</span>: <span class="pl-smi">boolean</span><span class="pl-kos">;</span>
  <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-k">private</span> <span class="pl-s1">accordion</span>: <span class="pl-smi">Accordion</span><span class="pl-kos">)</span><span class="pl-kos">{</span>
    <span class="pl-s1">accordion</span><span class="pl-kos">.</span><span class="pl-en">register</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
  <span class="pl-en">setActive</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">{</span>
    <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">accordion</span><span class="pl-kos">.</span><span class="pl-en">toggleActive</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">Ideally, a child component would simply expose a 'select' event:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="@Component({selector: 'accordion-item' })
class AccordionItem {
  @Input() active: boolean;
  @Output selected:EventEmitter&lt;AccordionItem&gt; = new EventEmitter();
  active: boolean;
  setActive(){
    this.selected.emit(this);
  }
}"><pre class="notranslate">@<span class="pl-smi">Component</span><span class="pl-kos">(</span><span class="pl-kos">{</span><span class="pl-c1">selector</span>: <span class="pl-s">'accordion-item'</span> <span class="pl-kos">}</span><span class="pl-kos">)</span>
<span class="pl-k">class</span> <span class="pl-smi">AccordionItem</span> <span class="pl-kos">{</span>
  @<span class="pl-smi">Input</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">active</span>: <span class="pl-smi">boolean</span><span class="pl-kos">;</span>
  @<span class="pl-smi">Output</span> <span class="pl-c1">selected</span>:<span class="pl-smi">EventEmitter</span><span class="pl-kos">&lt;</span><span class="pl-smi">AccordionItem</span><span class="pl-kos">&gt;</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-smi">EventEmitter</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-c1">active</span>: <span class="pl-smi">boolean</span><span class="pl-kos">;</span>
  <span class="pl-en">setActive</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">{</span>
    <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">selected</span><span class="pl-kos">.</span><span class="pl-en">emit</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">The parent accordion can currently easily get ahold of the children via <code class="notranslate">@ViewChildren()</code> (or whatever) but there is a not a clean way to listen to events emitted from the children.</p>
<p dir="auto">Proposed Syntax:</p>
<p dir="auto">Implement a <code class="notranslate">@ObserveChildren</code> decorator (or similar) that would enable Observation of events emitted by child components:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="@Component({selector: 'accordion' })
class Accordion {
  //specify type and desired output to Observe.
  @ObserveChildren(AccordionItem, 'select') childSelections: Observable&lt;AccordionItem&gt;
  @ViewChildren(AccordionItem) children: Observable&lt;AccordionItem&gt;
  afterViewInit(){
    this.updates = Observable
      .combineLatest(this.children, this.childSelections, (children, selected) =&gt; ({children, selected}))
      .do(({children, selected) =&gt; children.map(child =&gt; { //update state }))
      .subscribe();
  }
  onDestroy(){
    this.updates.unsubscribe();
  }
}"><pre class="notranslate">@<span class="pl-smi">Component</span><span class="pl-kos">(</span><span class="pl-kos">{</span><span class="pl-c1">selector</span>: <span class="pl-s">'accordion'</span> <span class="pl-kos">}</span><span class="pl-kos">)</span>
<span class="pl-k">class</span> <span class="pl-smi">Accordion</span> <span class="pl-kos">{</span>
  <span class="pl-c">//specify type and desired output to Observe.</span>
  @<span class="pl-smi">ObserveChildren</span><span class="pl-kos">(</span><span class="pl-smi">AccordionItem</span><span class="pl-kos">,</span> <span class="pl-s">'select'</span><span class="pl-kos">)</span> <span class="pl-c1">childSelections</span>: <span class="pl-smi">Observable</span><span class="pl-kos">&lt;</span><span class="pl-smi">AccordionItem</span><span class="pl-kos">&gt;</span>
  @<span class="pl-smi">ViewChildren</span><span class="pl-kos">(</span><span class="pl-smi">AccordionItem</span><span class="pl-kos">)</span> <span class="pl-c1">children</span>: <span class="pl-smi">Observable</span><span class="pl-kos">&lt;</span><span class="pl-smi">AccordionItem</span><span class="pl-kos">&gt;</span>
  <span class="pl-en">afterViewInit</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">{</span>
    <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">updates</span> <span class="pl-c1">=</span> <span class="pl-smi">Observable</span>
      <span class="pl-kos">.</span><span class="pl-en">combineLatest</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">children</span><span class="pl-kos">,</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">childSelections</span><span class="pl-kos">,</span> <span class="pl-kos">(</span><span class="pl-s1">children</span><span class="pl-kos">,</span> <span class="pl-s1">selected</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">(</span><span class="pl-kos">{</span>children<span class="pl-kos">,</span> selected<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">)</span>
      <span class="pl-kos">.</span><span class="pl-c1">do</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-kos">{</span><span class="pl-s1">children</span><span class="pl-kos">,</span> <span class="pl-s1">selected</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-s1">children</span><span class="pl-kos">.</span><span class="pl-c1">map</span><span class="pl-kos">(</span><span class="pl-s1">child</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span> <span class="pl-c">//update state }))</span><span class="pl-s1"></span>
      <span class="pl-kos">.</span><span class="pl-en">subscribe</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
  <span class="pl-s1">onDestroy</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">{</span>
    <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">updates</span><span class="pl-kos">.</span><span class="pl-en">unsubscribe</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">cc <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/pkozlowski-opensource/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/pkozlowski-opensource">@pkozlowski-opensource</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/Foxandxss/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/Foxandxss">@Foxandxss</a></p>