Reputation: 5176
I have created an accordion component that fills the values dynamically provided by the parent component. What I am not able to achieve is that each accordion should respond to the respective click. Currently, no matter which accordion I click, it just collapses and expands the first one. Here is my code:
array-parent.component.ts
import { Component, AfterViewInit, OnInit } from '@angular/core';
@Component({
selector: 'my-array-parent',
templateUrl: './array-parent.component.html',
})
export class ArrayParentComponent implements OnInit {
private content: Test[];
ngOnInit(): void {
this.content = [{
heading: 'header1',
testData: [{
title: 'title1',
content: 'content1'
}, {
title: 'title2',
content: 'content2'
}]
}, {
heading: 'header2',
testData: [{
title: 'title1',
content: 'content1'
}, {
title: 'title2',
content: 'content2'
}]
}]
}
}
export class Test {
heading: string;
testData: TestItem[];
}
export class TestItem {
title: string;
content: string;
}
array-parent.component.html
<ng-container *ngFor="let item of content">
<my-array [data]="item"></my-array>
</ng-container>
array.component.ts
import { Component, Input, OnInit, AfterViewInit } from '@angular/core';
@Component({
selector: 'my-array',
templateUrl: './array.component.html'
})
export class ArrayComponent implements OnInit {
@Input() data: any;
private contentObj: any;
constructor() { }
ngOnInit(): void {
this.contentObj = this.data;
}
}
array.component.html
<h2>{{contentObj.heading}}</h2>
<div class="columnOne" id="accordion" role="tablist" aria-multiselectable="true">
<div *ngFor="let item of contentObj.testData;">
<div role="tab" id="headingone">
<h4>
<a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseone" aria-expanded="true" aria-controls="collapseone">
{{item.title}}
</a>
</h4>
<div id="collapseone" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingone">
<div class="panel-body">
{{item.content}}
</div>
</div>
</div>
</div>
</div>
What I really want to do is that each accordion should expand and collapse only when it is clicked. Currently, no matter which accordion I click only the first one expands and collapse. I know that it is because it gets a static ID. I tried a few possible options to assign a dynamic id to all the fields but haven't been successful. Any help is greatly appreciated.
Upvotes: 3
Views: 26527
Reputation: 5176
Thanks everyone for the help. @Zze I built further on your idea to get exactly what I wanted. Here is my code that works the was I wanted. As in my case I had multiple headings and multiple accordion objects inside them.
this.content = [{
heading: 'header1ds kfgdskg',
id: 1,
testData: [{
title: 'title1 ds;olfhsdjkl',
content: 'content1 sdkjfhdskj'
}, {
title: 'title2 asdlkgkf',
content: 'content2 dsaghfdsf'
}]
}, {
heading: 'header2 sdfdsfds',
id: 2,
testData: [{
title: 'title1 sdfdsfs',
content: 'content1 sdygfsdgf'
}, {
title: 'title2 bsdfdudtfsd',
content: 'content2 sdk;fgdsugkft'
}]
}]
}
Changed my html code to this
<h2>{{contentObj.heading}}</h2>
<div class="columnOne" [id]="'accordion' + contentObj.id" role="tablist" aria-multiselectable="true">
<div *ngFor="let item of contentObj.testData; let i = index;">
<div role="tab" [id]="'heading' + contentObj.id">
<h4>
<a role="button" data-toggle="collapse" [attr.data-parent]="'#accordion' + contentObj.id"
[href]="'#collapse' + contentObj.id + i" aria-expanded="true" [attr.aria-controls]="'collapse' + contentObj.id + i">
{{item.title}}
</a>
</h4>
<div [id]="'collapse' + contentObj.id + i" class="panel-collapse collapse in" role="tabpanel" [attr.aria-labelledby]="'heading' + contentObj.id">
<div class="panel-body">
{{item.content}}
</div>
</div>
</div>
</div>
</div>
Upvotes: 1
Reputation: 18805
You need to bind the attributes that bootstrap relies on to toggle the div's accordingly:
Being:
id
, href
, aria-controls
id
, aria-labeledby
Here is a snippet from the working example:
<div class="panel-heading" role="tab" [id]="'heading'+data.id">
<h4 class="panel-title">
<a role="button" data-toggle="collapse" data-parent="#accordion" [href]="'#collapse'+data.id" aria-expanded="true" [attr.aria-controls]="'collapse'+data.id">
{{data.header}}
</a>
</h4>
</div>
<div [id]="'collapse'+data.id" class="panel-collapse collapse" role="tabpanel" [attr.aria-labelledby]="'heading'+data.id">
<div class="panel-body">
{{data.content}}
</div>
</div>
https://stackblitz.com/edit/angular-osvv72
Note that we have to prefix the aria attributes because they are not native attributes to <div>
& <a>
.
Upvotes: 10
Reputation: 5889
In your array component you expect an input of array type but actually you are passing an element not an array:
<ng-container *ngFor="let item of content">
<my-array [data]="item" //Here the item is an object></my-array>
</ng-container>
//////////////////////////////////////////////
export class ArrayComponent implements OnInit {
@Input() data: any[]// You are expecting an array;
Try to pass your array:
<ng-container>
<my-array [data]="content" //Here the item is an object></my-array>
</ng-container>
Upvotes: 0