0

I have a landing page that implements an accordion. The number of groups in the accordion are managed by a list of objects defining the properties(title, active... etc.) Each panel of the accordion contains a specific sub component. I would like to define the groups as such:

@Component({
    selector: 'aa-home',
    template: require('./home.component.html'),
    styles: [require('./home.component.scss')],
    directives: [ACCORDION_DIRECTIVES, QUOTE_COMPONENTS]
})
export class HomeComponent implements OnInit {
    public oneAtATime: boolean = true;
    public groups: AccordianGroup[] = [];

    constructor() {
        this.groups.push(new AccordianGroup(true, 'Quote', 'quote', '<aa-quote (response)="onContinue($event)"></aa-quote>'));
        this.groups.push(new AccordianGroup(false, 'Introduction', 'intro', '<aa-intro (response)="onContinue($event)"></aa-intro>'));
        this.groups.push(new AccordianGroup(false, 'Applicant Information', 'applicant', '<aa-applicant (response)="onContinue($event)"></aa-applicant>'));
        this.groups.push(new AccordianGroup(false, 'Details', 'details', '<aa-details(response)="onContinue($event)"></aa-details>'));
        this.groups.push(new AccordianGroup(false, 'Review', 'review', '<aa-review (response)="onContinue($event)"></aa-review>'));
        this.groups.push(new AccordianGroup(false, 'Payment', 'payment', '<aa-payment (response)="onContinue($event)"></aa-payment>'));
    }

    ngOnInit() {
        console.log(_.capitalize('starting home'));
    }

    onContinue(message): void {
        let index = _.findIndex(this.groups, function(x) { return x.name === message.componentName; });
        if (index < this.groups.length - 1) {
            this.groups[index].isActive = false;
            this.groups[index + 1].isActive = true;
        }
    }

    toggleActive(group): void {
        this.groups.forEach(function(x) { x.isActive = false; });
        group.isActive = !group.isActive;
    }
}

class AccordianGroup {
    constructor(
      public isActive: boolean,
      public title: string,
      public name: string,
      public template: string
    ) { }
}

The HTML like this:

<div *ngFor="let group of groups">
    <div class="accordion" (click)=toggleActive(group)>{{group.title}}</div>
    <div class="panel" [ngClass]="{show: group.isActive}" [innerHTML]="group.template"></div>
</div>

This doesn't work... nothing is rendered. It feels as if I'm going about this the wrong way but I'm not able to sort this out. The idea behind this is that depending on the user... I need to filter some groups out and really... not have a dozen or more groups in the html that have the exact same code except for the one line where the sub component is placed. Is this even possible?

ASG
  • 31
  • 3

1 Answers1

0

You can't create components with new. Components are either created by Angular from the HTML in the view for from ViewContainerRef.createComponent()

For a ViewContainerRef.createComponent() example see Angular 2 dynamic tabs with user-click chosen components (it's quite a similar use case)

To create components from markup build the data (model) in the parent components class and then use the selector of AccordianGroup to create the elements.

public groups: AccordianGroup[] = [];
constructor() {
    this.groups = [...];
...
}
<div *ngFor="let group of groups">
    <div class="accordion" (click)=toggleActive(group)>{{group.title}}</div>
    <div class="panel" [ngClass]="{show: group.isActive}"><accordian-group [data]="group.data"></accordian-group></div>
</div>
Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • I updated the original post. The sub components exist and this works if i explicitly add each group to the mark up. There is a bit more fluff in the mark up for images and such so for the most part the only differences from one group to another is the one line where the sub component goes. Seems like a lot of duplicated code. – ASG May 13 '16 at 20:21
  • If `AccordianGroup` is a component, this won't work. – Günter Zöchbauer May 13 '16 at 20:30
  • AccordionGroup is an object defined at the bottom of the first code block in the original post. The constructor is creating and initializing the groups. Each group is associated with a sub component and that is where I am trying to find a way to output the sub components associated with each group. – ASG May 13 '16 at 20:44