0

What I am trying to do:

I am trying to have collapsible accordion style items on a page which will expand and collapse on a click event. They will expand when a certain class is added collapsible-panel--expanded.

How I am trying to achieve it:

On each of the items I have set a click event like so:

<div (click)="toggleClass()" [class.collapsible-panel--expanded]="expanded" class="collapsible-panel" *ngFor="let category of categories">
    ....
</div>
<div (click)="toggleClass()" [class.collapsible-panel--expanded]="expanded" class="collapsible-panel" *ngFor="let category of categories">
    ....
</div>

and in the function toggleClass() I have the following:

expanded = false;
toggleClass() {
    this.expanded = !this.expanded;
    console.log(this.expanded)

}

The issue im facing:

When I have multiple of this on the same page and I click one, they all seem to expand.

I cannot seen to get one to expand.

Edit:

The amount of collapsible links will be dynamic and will change as they are generated and pulled from the database. It could be one link today but 30 tomorrow etc... so having set variable names like expanded 1 or expanded 2 will not be viable

Edit 2:

Ok, so the full code for the click handler is like so:

toggleClass(event) {
    event.stopPropagation();
    const className = 'collapsible-panel--expanded';
    if (event.target.classList.contains(className)) {
        event.target.classList.remove(className);
        console.log("contains class, remove it")
    } else {
        event.target.classList.add(className);
        console.log("Does not contain class, add it")
    }

}

and the code in the HTML is like so:

<div (click)="toggleClass($event)" class="collapsible-panel" *ngFor="let category of categories" >
  <h3 class="collapsible-panel__title">{{ category }}</h3>
  <ul class="button-list button-list--small collapsible-panel__content">
      <div *ngFor="let resource of resources | resInCat : category">
          <a href="{{ resource.fields.resource.fields.file.url }}" target="_blank" class="button-list__inner no-decoration doc"><span class="underline display-block margin-bottom">{{ resource.fields.title }}</span><span class="secondary" *ngIf="resource.fields.description display-block">{{ resource.fields.description }}</span></a>
      </div>
  </ul>
</div>

5 Answers 5

2

you could apply your class through javascript

<div (click)="handleClick($event)">
    some content
</div>

then your handler

handleClick(event) {
    const className = 'collapsible-panel--expanded';
    if (event.target.classList.contains(className)) {
        event.target.classList.remove(className);
    } else {
        event.target.classList.add(className);
    }
}

In plain html and js it could be done like this

function handleClick(event) {
    const className = 'collapsible-panel--expanded';
    if (event.target.classList.contains(className)) {
        event.target.classList.remove(className);
    } else {
        event.target.classList.add(className);
    }
    console.log(event.target.classList.value);
}
<div onclick="handleClick(event)">
some content
</div>

Sign up to request clarification or add additional context in comments.

10 Comments

Hey so this is the only answer that is working, however there is a slight change I need some help with. inside the div there is a h3 tag. When I click it is adding the class to the h3 even thought I have the click event bound to the parent div. I think somehow it is filtering down to the h3. Is there a way to stop this?
yes. you can use event.stopPropogation
call that before anything else and it stop the event from passing down the html tree
so I added it to the toggleClass function at the very top but it didnt work.
event.stopPropogation() doesnt work? maybe you could show me more code
|
2
Try to pass unique Id. (little modification)Ex: -

in component.ts file: 
selectedFeature: any;
categories:any[] = [
        {
          id: "collapseOne",
          heading_id: "headingOne",
        },
        {
          id: "collapseTwo",
          heading_id: "headingTwo",
        },
        {
          id: "collapseThree",
          heading_id: "headingThree",
        }
];

toggleClass(category) {
this.selectedFeature = category;
};

ngOnInit() {
this.selectedFeature = categories[0]
  }

in html:-

<div class="collapsible-panel" *ngFor="let category of categories">
<!-- here you can check the condition and use it:-
ex:
<h4 class="heading" [ngClass]="{'active': selectedFeature.id==category.id}" (click)="toggleClass(category)">
<p class="your choice" *ngIf="selectedFeature.id==category.id" innerHtml={{category.heading}}></p>

   enter code here

 -->
.....
</div>

1 Comment

in "active" class put your css style
1

Try maintaining an array of expanded items.

expanded = []; // take array of boolean 
toggleClass(id: number) {
    this.expanded[i] = !this.expanded[i];
    console.log(this.expanded[i]);
}

2 Comments

and how would I get that to check here: [class.collapsible-panel--expanded]="expanded" ?
you can use index expanded[index] to get the values. you use the index of the html element according to the way you put
0

Your solution will be the usage of template local variables:

see this: https://stackoverflow.com/a/38582320/3634274

1 Comment

I am afraid I do not know what you mean or even how to start. My template has a variable defined in the .ts file. Could you provide a code solution?
0

You are using the same property expanded to toggle for all the divs, so when you set to true for one div, it sets it true for all the divs.

Try setting different properties like this:

<div (click)="toggleClass("1")" [class.collapsible-panel--expanded]="expanded1" class="collapsible-panel" *ngFor="let category of categories">
    ....
</div>
<div (click)="toggleClass("2")" [class.collapsible-panel--expanded]="expanded2" class="collapsible-panel" *ngFor="let category of categories">
    ....
</div>

TS:

expanded1 = false;
expanded2 = false;

toggleClass(number:any) {
    this["expanded" + number]  = !this["expanded" + number];
    console.log(this["expanded" + number]) 
}

2 Comments

Please see my edit, I apologise as I was not clear, the amount of collapsible divs needs to be dynamic as it will change on a daily basis and therefore having set variables like expanded1/2/3/4 will not do.
Instead of having hard-coded numbers, please use the index from ngFor

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.