title: Angular 2: Trouble with Custom Components
body: <p>I am currently trying to get a custom component working within Angular 2 written with ES6/ES7 and transpiled with <code>Babel</code>. </p>
  
  <p>When I load up the page, I get the component accordion with all of the appropriate data present, but all of the panels are shut and clicking does nothing. I am modelling my accordion after this <code>TypeScript</code> <a href="http://plnkr.co/edit/PvKuiBon0PpM6sNSehc6?p=preview" rel="nofollow noreferrer">Plunker</a>. Additionally, the removeDynamic() function from <code>AppComponent</code> toggles when you click the button but the view does not update to show the change in data. I am at a loss after spending the better part of yesterday and today tinkering with it. Any insight would be much appreciated!</p>
  
  <p>I have my <code>AppComponent</code> defined as such, with an appropriate template:</p>
  
  <pre><code>import {Component, View} from 'angular2/core'; // Import Component and View constructor (for metadata)
  import {HTTP_PROVIDERS} from 'angular2/http'; // We're using http in our
  
  import {Accordion, AccordionGroup} from '../components/accordion/accordion.component';
  
  // Import NgFor directive
  import {NgFor} from 'angular2/common';
  
  // Annotate AppComponent class with `Component`
  @Component({
    selector: 'my-app',
  
    // Let Angular know about `Http`
    providers: [HTTP_PROVIDERS]
  })
  
  
  // Define the view of our `Component` using one or more
  // `View` annotations
  @View({
  
    // Link to our external template file
    templateUrl: './components/app.html',
  
    // Specify which directives our `Component` will utilize with
    // the `directive` property of the `View` annotation
    directives: [Accordion, AccordionGroup, NgFor]
  })
  
  export class AppComponent {
    constructor() {
  
      // Debug
      console.log('AppComponent constructor() go');
  
      this.isOpen = false;
  
      this.groups = [
        {
          heading: 'Dynamic 1',
          content: 'I am dynamic!'
        },
        {
          heading: 'Dynamic 2',
          content: 'I am dynamic as well'
        }
      ];
    }
  
    removeDynamic() {
      this.groups.pop();
  
      // Debug
      console.log('removeDynamic() run');
    }
  };
  
  //export {AppComponent};
  </code></pre>
  
  <p>The template for <code>AppComponent</code>:</p>
  
  <pre><code>&lt;p&gt;
    &lt;button type="button" class="btn btn-default" (click)="removeDynamic()"&gt;
      Remove last dynamic
    &lt;/button&gt;
  &lt;/p&gt;
  
  &lt;accordion&gt;
    &lt;accordion-group heading="This is the header" is-open="true"&gt;
      This is the content
    &lt;/accordion-group&gt;
    &lt;accordion-group [heading]="group.heading" *ngFor="#group of groups"&gt;
      {{group.content}}
    &lt;/accordion-group&gt;
    &lt;accordion-group heading="Another group" [is-open]="isOpen"&gt;
      More content
    &lt;/accordion-group&gt;
  &lt;/accordion&gt;
  </code></pre>
  
  <p>My Angular app is bootstrapped elsewhere due to Webpack.</p>
  
  <p>I have a custom <code>Accordion</code> component written using Angular 2 with ES6/ES7:</p>
  
  <pre><code>// Import Inject, Component and View constructor (for metadata)
  import {Inject} from 'angular2/core';
  import {Component, View} from 'angular2/core';
  // Import NgClass directive
  import {NgClass} from 'angular2/common';
  
  // # Accordion Component
  
  // Annotate Accordion class with `Component`
  @Component({
    // Define how we can use our `Component` annotation with
    // the `selector` property. 
    selector: 'accordion, [accordion]',
  
    // Modify the `host` element with a css class designator
    host: {
      'class': 'panel-group'
    }
  })
  
  // Define the view of our `Component` using one or more
  // `View` annotations
  @View({
  
    // Link to our external template file
    templateUrl: './components/accordion/accordion.html'
  })
  
  // Create and export `Component` class
  export class Accordion {
  
    constructor() {
      // Debug
      console.log('Accordion constructor() go');
  
      this.groups = [];
    }
  
    // Function to register groups
    addGroup(group) {
      this.groups.push(group);
    }
  
    closeOthers(openGroup) {
      this.groups.forEach((group) =&gt; {
        if(group !== openGroup) {
          group.isOpen = false;
        }
      });
    }
  
    removeGroup(group) {
      let index = this.groups.indexOf(group);
  
      if(index !== -1) {
        this.groups.splice(index, 1);
      }
    }
  }
  
  // # AccordionGroup Component
  
  // Annotate AccordionGroup class with `Component`
  @Component({
    selector: 'accordion-group, [accordion-group]',
  
    // Specify (with the `inputs` property) that we are using a `heading`
    // attribute in our  component which will be mapped to a `heading`
    // variable in our `Component`.
    inputs: ['heading', 'isOpen'],
  
    // Let Angular know about any `providers`
    providers: []
  })
  
  // Define the view of our `Component` using one or more
  // `View` annotations
  @View({
  
    // Link to our external template file
    templateUrl: './components/accordion/accordion-group.html',
  
    // Specify which directives our `Component` will utilize with
    // the `directive` property of the `View` annotation
    directives: [NgClass, Accordion]
  })
  
  // Create and export `Component` class
  export class AccordionGroup {
  
    constructor(accordion) {
      // Debug
      console.log('AccordionGroup constructor() go');
  
      this._isOpen = false;
  
      this.accordion = accordion;
  
      this.accordion.addGroup(this);
    }
  
    // Angular 2 DI desugar'd
    // Reference: https://stackoverflow.com/questions/33026015/how-to-inject-angular2-http-service-into-es6-7-class
    /*static get parameters() {
      return [[Accordion]];
    }*/
  
    toggleOpen(event) {
      event.preventDefault();
      this.isOpen = !this.isOpen;
      this.accordion.closeOthers(this);
    }
  
    onDestroy() {
      this.accordion.removeGroup(this);
    }
  }
  
  // The above desugar'd Angular 2 DI should work, but doesn't. This
  // line seems to accomplish what we are looking for though.
  AccordionGroup.parameters = [[Accordion]];
  
  //export {Accordion, AccordionGroup};
  </code></pre>
  
  <p>This is the template for the <code>Accordion</code> component:</p>
  
  <pre><code>&lt;ng-content&gt;&lt;/ng-content&gt;
  </code></pre>
  
  <p>And the template for my <code>AccordionGroup</code> component:</p>
  
  <pre><code>&lt;div class="panel panel-default" [ngClass]="{'panel-open': isOpen}"&gt;
    &lt;div class="panel-heading" (click)="toggleOpen($event)"&gt;
      &lt;h4 class="panel-title"&gt;
        &lt;a href tabindex="0"&gt;&lt;span&gt;{{heading}}&lt;/span&gt;&lt;/a&gt;
      &lt;/h4&gt;
    &lt;/div&gt;
    &lt;div class="panel-collapse" [hidden]="!isOpen"&gt;
      &lt;div class="panel-body"&gt;
        &lt;ng-content&gt;&lt;/ng-content&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>As an aside, a lot of the code came from this particular tutorial which demonstrates all of the Angular 2 stuff with TypeScript, so I simply adapted it to my es6/es7 environment with Webpack | <a href="http://angular-tips.com/blog/2015/09/migrating-directives-to-angular-2/" rel="nofollow noreferrer">Migrating Directives to Angular 2</a></p>
  
  <p>Update: I have attempted both of the answers submitted and neither has solved the problem of the view not updating.</p>
  
  <p>Here is a screen capture of how the component is currently behaving:</p>
  
  <p><a href="https://i.stack.imgur.com/oSPzc.gif" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/oSPzc.gif" alt="The proper data is present, yet the view isn&#39;t updating"></a></p>
  
  <p>And another of the debug logs showing data manipulation:</p>
  
  <p><a href="https://i.stack.imgur.com/g1c1f.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/g1c1f.png" alt="The appropriate data manipulation is present, but I am at a loss"></a></p>
  
  <p>I am at a loss here guys, and I really can't use TypeScript :(</p>