Is there a way to have my accordion adjust automatically?

I have developed a dynamic accordion component that populates its values from the parent component. However, I am facing an issue where each accordion does not respond individually to clicks. Whenever I click on any accordion, only the first one expands and collapses. Below is the code snippet:

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>

My goal is to make each accordion expand and collapse individually upon clicking. Currently, only the first accordion responds because of the static ID assigned. I've tried assigning dynamic IDs but without success. Any assistance in resolving this issue would be highly appreciated.

Answer №1

To make Bootstrap work properly with your div elements, you must bind the necessary attributes:

These include:

  • panel-heading: id, href, aria-controls
  • panel-collapse: id, aria-labeledby

Check out a snippet of a functional example below:

<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

Remember to add prefixes to the aria attributes since they are not default attributes for <div> or <a> elements.

Answer №2

Appreciation to all for the assistance. @Zze, I expanded on your suggestion to achieve my desired outcome. Below is the code that perfectly fulfills my requirements, especially since I had multiple headings and accordion elements nested within 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'
            }]
        }]
    }

Modified my HTML structure as follows:

<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>

Answer №3

When working with your array component, make sure to pass an actual array as input instead of just an element:

<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[]// Ensure you are passing an array;

Make sure to pass the array correctly like this:

<ng-container>
      <my-array [data]="content" //Here the item is an object></my-array>
</ng-container>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the method for including word boundaries in a regex constructor?

export enum TOKENS { CLASS = 1, METHOD, FUNCTION, CONSTRUCTOR, INT, BOOLEAN, CHAR, VOID, VAR, STATIC, FIELD, LET, DO, IF, ELSE, WHILE, RETURN, TRUE, FALSE, NULL, THIS } setTokenPatterns() { let tokenString: s ...

Is there a way to eliminate the white border surrounding this input field? (JSFiddle link included)

http://jsfiddle.net/gn3LL/ .error { background-color: red; } <input id="firstname" class="custom error" name="first_name" type="text" placeholder="" class="input-xlarge"> I am trying to remove the small white border around the inside of the inpu ...

Ways to extend the default timeout duration in Angular

My server calls are taking a long time, around 30-40 minutes, and my Angular frontend is timing out. Is there a way to increase the default timeout for this service call? method1(id: number): Promise<number> { const body= JSON.stringify(id); ...

Angular 6 component experiencing issues with animation functionality

I've implemented a Notification feature using a Notification component that displays notifications at the top of the screen. The goal is to make these notifications fade in and out smoothly. In my NotificationService, there's an array that holds ...

unfamiliar element detected in custom component

I recently created a simple component in Ionic as a test. I used the Ionic CLI to generate the component, and here is an excerpt from my app.module.ts file: import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/p ...

Having trouble sending data with a POST request using Angular 4's HttpClient?

Angular 4.4.4 This is an introduction to my app component constructor( private http: HttpClient, ) this.http.post('/api.php', {name, age}).subscribe(response => { console.log(response); }); api.php -> exit(json_encode($_P ...

Angular 6: A guide to dynamically highlighting navbar elements based on scroll position

I am currently building a single page using Angular 6. The page is quite basic, and my goal is to emphasize the navbar based on scrolling. Below is the code snippet I am working with: .sticky { position: sticky; top: 0; } #i ul { list-style-type: ...

Endpoint not returning data as expected

I'm facing an issue with my routing module where I have successfully used activatedRoute for multiple other modules but now running into trouble when implementing it in a new singular component. The structure of my routing module is as follows: const ...

The mat-autocomplete feature is sending multiple requests to the server instead of just one

After inputting a few characters, my code is designed to make a GET request and auto-complete the returned JSON object. However, I noticed that even after stopping typing for a few seconds, the backend is being hit multiple times rather than just once (I h ...

Updating Bootstrap Indicators with jQuery on Click Event

Unfortunately, I am unable to share an image due to limited internet data. My goal is to switch each image to its sprite equivalent. There are three list items that I'm struggling to change because they each have two classes that need to be updated. ...

Having trouble importing .task files in a Next.js project with TypeScript?

I encountered an issue when trying to import a model.task file into my App.tsx file. After training a hand gesture recognition model in Python, I exported it to a model.task file. Now, I am attempting to import this file into my Next.js + Typescript proje ...

Utilizing a function within the catchError method

A function has been defined to handle errors by opening a MatSnackBar to display the error message whenever a get request encounters an error. handleError(err: HttpErrorResponse) { this.snackBar.open(err.message) return throwError(err) } When subs ...

DiscoverField Component with Button Functionality and Checkbox Dilemma

I'm working with Vue 3, Vuetify, and TypeScript for my searchField component. Inside, I have two buttons: FreeItemMaster and PatternMaster. Clicking on these buttons should change their background color and display respective content below them. Howev ...

The image appears to be overlapping within the navigation bar

I'm having trouble understanding why the image is overlapping on this website. The image is enclosed in a link tag, and upon inspecting it, the link tag seems to be correctly positioned while the image appears slightly below. I can't seem to ide ...

Transform a flat 2D shape into a dynamic 3D projection using d3.js, then customize the height based on the specific value from ANG

Currently, I am utilizing d3.js version 6 to generate a 3D representation of the 2D chart shown below. Within this circle are numerous squares, each colored based on its assigned value. The intensity of the color increases with higher values. My goal is t ...

Guide on verifying the snack bar's visibility and performing an action in e2e test using Protractor

Currently, I am conducting e2e testing using Protractor and encountering an issue with the snack bar feature. Here is a screenshot of the functioning app: Demo The dilemma lies in verifying the visibility of the snackbar on the page and how to execute the ...

When using Angular 2 formControl, manually changing the value may not be detected by the form

Having a simple form (as shown below), I am encountering an issue: Manually entering input value causes form.controls['myValue'].value to change If #myInput value is changed programmatically, the form completely ignores that change What could ...

What is the most effective way to retrieve data from a URL and process it using reactjs?

Looking to consume JSON data from a URL, here is an example of the JSON structure: { "results": [ ... ], "info": { ... } } I aim to display the fetched data as a component property. What is the most efficient way to achie ...

The issue I'm facing with Angular 8 is that while the this.router.navigate() method successfully changes the URL

As someone who is relatively new to Angular, I am currently in the process of setting up the front end of a project using Angular 8. The ultimate goal is to utilize REST API's to display data. At this point, I have developed 2 custom components. Logi ...

Angular 7 and its scrolling div

Currently, I am working on implementing a straightforward drag and drop feature. When dragging an item, my goal is to scroll the containing div by a specified amount in either direction. To achieve this, I am utilizing Angular Material's CDK drag an ...