Bootstrap panels within Thymeleaf loop - same id and href - javascript

I'm trying to generate bootstrap collapse panels within Thymeleaf loop, like that:
<table>
<tr th:each="p, iterStat : ${completedList}">
<td style="padding: 0 15px 0 15px;">
<div class="panel panel-success">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion"
href="#collapseOne" th:text="${p.key}">p.k</a>
<span style="float: right;" class="glyphicon glyphicon-ok"></span>
</h4>
</div>
<div th:id="collapseOne" class="panel-collapse collapse in">
<div class="panel-body">
<span th:text="${p.value}"></span>
</div>
</div>
</div>
</td>
</tr>
</table>
But I have the same id and href for every element of the loop so the panels doesn't works.
Can I do something to change dynamically id and href?

You can use the status variable (iterStat) to create a unique id for every row:
<a data-toggle="collapse" data-parent="#accordion" th:href="'#collapse' + ${iterStat.index}" th:text="${p.key}">
and
<div th:id="'collapse' + ${iterStat.index}" class="panel-collapse collapse in">

I just ran into this same issue and what I did was
<div class="accordion" id="accordionExample"
th:each="todo : ${todos}">
<div class="accordion-item">
<h2 class="accordion-header" th:id="heading + ${todo.id}">
<button class="accordion-button" type="button"
data-bs-toggle="collapse"
th:attr="data-bs-target=|#col${todo.id}" aria-expanded="true"
aria-controls="collapseOne">Accordion Item #1</button>
</h2>
<div th:id="col + ${todo.id}"
class="accordion-collapse collapse show"
th:attr="aria-labelledby=|heading${todo.id}|"
data-bs-parent="#accordionExample">
<div class="accordion-body">
<strong>This is the first item's accordion body.</strong> It
is shown by default, until the collapse plugin adds the
appropriate classes that we use to style each element. These
classes control the overall appearance, as well as the showing
and hiding via CSS transitions. You can modify any of this
with custom CSS or overriding our default variables. It's also
worth noting that just about any HTML can go within the
<code>.accordion-body</code>
, though the transition does limit overflow.
</div>
</div>
</div>
</div>
instead of concatenating the id, just add it as a string with the th:attr, then the value should be put inside the | {dynamic value e.g id, uuid, primary key} |.
then concatenate with the + for the th:id which will automatically know its equivalent attribute as set earlier.

Related

JavaScript- Not showing the Title in Text Accordion

At first Please see the screenshot , here i am working on Accordion text Editor, where you can add title and body text.
when i clicked ADD button multiple time then showing like this type. Not showing the title text. i thing it's problem on JS file. Does any solution??
Thanks in Advance!
$(document).ready(function() {
$('#Add_btn').click(function(){
$('#accordion_body').append($('#editableDiv').html());
var x = document.getElementById("accordion_input").value;
document.getElementById("accordion_title").innerHTML = x;
});
});
function myAccorFunction() {
var Myaccordion = `
<div class="Myacc" id="acc_main" contenteditable="false"
class="accordion-main"
style="position: relative;width: 98.5%; left: 9px;">
</div>
<div class="panel-group trash_removed" id="accordion" role="tablist"
aria-multiselectable="true"
style="margin-bottom: 7px;margin-top: 10px"
contenteditable="false">
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingOne"
contenteditable="false">
<h4 class="panel-title">
<a id="accordion_title" role="button" data-toggle="collapse"
data-parent="#accordion" href="#expandingCol"
aria-expanded="false" aria-controls="collapseOne">
</a><div class="icon_area">
<i class="fa fa-edit" data-toggle="collapse"
data-parent="#accordion" href="#collapseOne"
aria-expanded="false" aria-controls="collapseOne">
</i>
<i onclick="myfundelete()" class="fa fa-trash">
</i>
</div>
</h4>
</div>
<div id="expandingCol" class="panel-collapse collapse"
role="tabpanel" aria-labelledby="headingOne">
<div id="accordion_body" class="panel-body" >
</div>
</div>
</div>
</div>
`;
$("#editor").append(Myaccordion);
}
<button onclick="myAccorFunction()" id="Add_btn"
class="btn btn-primary note-image-btn" role="button"
data-toggle="collapse" data-parent="#accordion"
href="#collapseOne" aria-expanded="true"
aria-controls="collapseOne">Add</button>
It appears you are using the same element ID #accordion_title more than once. As browsers assume element ID is unique within a page, document.getElementById("accordion_title").innerHTML = x; will only change the innerHTML of the first element having that ID, but not the subsequent ones that were appended by the ADD button.
Try using a Class name instead of ID for your title text element, then iterate over every element of that class to change their innerHTML.
$('.accordion_title').each(function() {
$(this).html($('#accordion_input').val());
});

Dynamically set class or id using index of ngFor loop

So I am trying to create a collapse (accordion) in Bootstrap 4 using Angular. I would love to be able to create almost the entire thing using an ngFor loop.
So far I have this:
<div class="row">
<div class="col-lg-6">
<div id="accordion" role="tablist" aria-multiselectable="true">
<div class="card" *ngFor="let environment of environments; let i = index;">
<div class="card-header" role="tab" id="headingi">
<h5 class="mb-0">
<a data-toggle="collapse" data-parent="#accordion" href="#collapsei" aria-expanded="false" aria-controls="collapsei">
Number: {{i}}
</a>
</h5>
</div>
<div id="collapseOne" class="collapse show" role="tabpanel" aria-labelledby="headingOne">
<div class="card-block">
<div *ngFor="let name of uniqueNames; let j = index" class="card infoBox">
<p>this is accordion {{i}}, section: {{j}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
What I am trying to do is use "let i = index" to set the id and class names needed to make the accordion know what to do when certain links are clicked. So ideally the first accordion section would have class and id of collapse0/heading0 and the next would have id and class of collapse1/heading1 etc.
However, the previous code must not be working because all the accordions and their headers show up and do nothing when clicked on. It does generate the correct number, show all the right headers, and the bodies associated with them.
Any help? thanks!
You can do it this way also
id="collapse{{i}}" class="heading{{i}}" attr.aria-controls="heading{{i}}"
and the fact that aria- attributes are being handled another way in angular you have to prefix them with attr.. In your example should that be attr.aria-controls="heading{{i}}".
You just have to databind id:
<div class="card-header" role="tab" [id]="'heading'+i">
<!-- and -->
<div [id]="'collapse' + i" class="collapse show" role="tabpanel" [aria-labelledby]="'heading' + i">
And then you can access your index via i.
*Here is working code with bootstrap 5 accordion with ngFor Angular 12 (dynamic id):
<div class="accordion" id="accordionPanelsStayOpenExample">
<div class="accordion-item">
<h2 class="accordion-header" id="panelsStayOpen-headingOne">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#panelsStayOpen-collapseOne" aria-expanded="true" aria-controls="panelsStayOpen-collapseOne">
Installed Offer Version Details
</button>
</h2>
<div id="panelsStayOpen-collapseOne" class="accordion-collapse collapse show" aria-labelledby="panelsStayOpen-headingOne">
<div class="accordion-body">
<ng-container *ngFor="let lineItem of allLineItems">
<!-- <line-item-detail [lineItem]="lineItem"></line-item-detail>-->
<div class="accordion-item my-4">
<h2 class="accordion-header" id="heading{{lineItem.id}}">
<button class="accordion-button" type="button" data-bs-toggle="collapse" attr.data-bs-target="#collapse{{lineItem.id}}" aria-expanded="true" attr.aria-controls="collapse{{lineItem.id}}">
{{lineItem.productType}} : {{lineItem?.productOffering?.name}}
</button>
</h2>
<div id="collapse{{lineItem.id}}" class="accordion-collapse collapse show" attr.aria-labelledby="heading{{lineItem.id}}">
<div class="accordion-body">
your body text
</div>
</div>
</div>
</ng-container>
</div>
</div>
</div>
</div>
Even you can create sub-component of what is in ngFor like I commented the <line-item-detail></line-item-detail> tag.

Bootstrap collapsible breaks on combox select change

My collapsible div looks like this and it collapse/expand on clicking btnCollapse.
As soon as I change the selection in dropdown, the collapsible div stop expanding. What am I doing wrong ? Any hints please ?
<div class="panel-heading" style="padding-bottom:20px;">
<h4 class="panel-title">
<a data-toggle="collapse" id="btnCollapse" href="#collapse1" style="float:right;">Hide Filter</a>
</h4>
</div>
<div id="collapse1" class="panel-collapse collapse in">
<div class="col-sm-6">
#Html.DropDownListFor(m=>m.SelectedCat,new SelectList(Model.Cat, "Id", "Name"),"Select ..",new { #class= "form-control" })
</div>
</div>

How to collapse content and change glyphicon in buttons right in bootstrap?

In the lack of my javascript-skills I need some help for my very basic bootstrap problem.
That's the goal: four hidden paragraphs via collapse and a "toggle" button for each to make it visible or hidden.
That's the problem: the first collapse works fine, but the second, third and fourth glyphicon inside the buttons is changing too. And if I want to view the second, third and fourth collapsed paragraph after clicking the appropriate button it only shows the first paragraph. What happen? Is there only the one way to make this works, to include different IDs for each paragraph in the Javascript?
Live on Bootply: http://www.bootply.com/Jyf06v1aiK
<div class="col-xs-6">
<div class="collapse" id="collapseDiv">
<p class="">This is the FIRST collapsible content!</p>
</div>
<button data-toggle="collapse" data-target="#collapseDiv">
<span class="glyphicon glyphicon-large glyphicon-menu-down"></span>
</button>
</div>
<div class="col-xs-6">
<div class="collapse" id="collapseDiv">
<p class="">This is the SECOND collapsible content!</p>
</div>
<button data-toggle="collapse" data-target="#collapseDiv">
<span class="glyphicon glyphicon-large glyphicon-menu-down"></span>
</button>
</div>
<div class="col-xs-6">
<div class="collapse" id="collapseDiv">
<p class="">This is the THIRD collapsible content!</p>
</div>
<button data-toggle="collapse" data-target="#collapseDiv">
<span class="glyphicon glyphicon-large glyphicon-menu-down"></span>
</button>
</div>
<div class="col-xs-6 bg-success">
<div class="collapse" id="collapseDiv">
<p class="">This is the FOURTH collapsible content!</p>
</div>
<button data-toggle="collapse" data-target="#collapseDiv">
<span class="glyphicon glyphicon-large glyphicon-menu-down"></span>
</button>
</div>
Javascript:
$('#collapseDiv').on('shown.bs.collapse', function () {
$(".glyphicon").removeClass("glyphicon-menu-down").addClass("glyphicon-menu-up");
});
$('#collapseDiv').on('hidden.bs.collapse', function () {
$(".glyphicon").removeClass("glyphicon-menu-up").addClass("glyphicon-menu-down");
});
Take a look at my changes on your code here.
Your issue is not actually related to JS, but to concepts around the DOM.
First of all, it isn't a good idea to have the same id in multiple elements, the id attribute is supposed to be unique across the entire DOM.
Second, $('.glyphicon') refers to ALL the elements in the DOM with a class glyphicon not only the closest to your collapse div.
I'm including the code here but feel free to try it in the link above.
<div class="container">
<h1 class="">Bootstrap Collapse Buttons (WIP)</h1>
<div class="col-xs-6 bg-warning">
<div class="collapse customCollapse" id="collapseDiv">
<p class="">This is the FIRST collapsible content!</p>
</div>
<button data-toggle="collapse" data-target="#collapseDiv" class=""> <span class="glyphicon glyphicon-large glyphicon-menu-down"></span>
</button>
</div>
<div class="col-xs-6 bg-info">
<div class="collapse customCollapse" id="collapseDiv2">
<p class="">This is the SECOND collapsible content!</p>
</div>
<button data-toggle="collapse" data-target="#collapseDiv2" class=""> <span class="glyphicon glyphicon-large glyphicon-menu-down"></span>
</button>
</div>
<div class="col-xs-6 bg-danger">
<div class="collapse customCollapse" id="collapseDiv3">
<p class="">This is the FIRST collapsible content!</p>
</div>
<button data-toggle="collapse" data-target="#collapseDiv3" class=""> <span class="glyphicon glyphicon-large glyphicon-menu-down"></span>
</button>
</div>
<div class="col-xs-6 bg-success">
<div class="collapse customCollapse" id="collapseDiv4">
<p class="">This is the SECOND collapsible content!</p>
</div>
<button data-toggle="collapse" data-target="#collapseDiv4" class=""> <span class="glyphicon glyphicon-large glyphicon-menu-down"></span>
</button>
</div>
</div>
And the js
$('.customCollapse').on('shown.bs.collapse', function () {
$(this).parent().find(".glyphicon").removeClass("glyphicon-menu-down").addClass("glyphicon-menu-up");
});
$('.customCollapse').on('hidden.bs.collapse', function () {
$(this).parent().find(".glyphicon").removeClass("glyphicon-menu-up").addClass("glyphicon-menu-down");
});
EDIT
A little extra explanation: if you plan to share js logic across multiple DOM elements a good way to do it is using classes. That is why I changed your js and DOM to use .customCollapse instead of the collapseDiv id.
Note also that I changed the ids on each collapseDiv by adding a number to make it unique.

Collapse nested accordion groups based on custom class

I'm using Twitter Bootstrap 2.3.2 with Asp.net MVC.
I have a set of nested accordions on a tab pane and other accordions on other tab panes.
The External accordions are in an accordion-group and the Internal accordions are in another group, nested inside each External accordion.
The colours are applied using CSS rules on custom classes.
.accordion-toggle.outcome {
background-color:#d9edf7;
}
.accordion-toggle.outcome.collapsed {
background-color:White;
}
.accordion-toggle.achievement {
background-color:#dff0d8;
}
.accordion-toggle.achievement.collapsed {
background-color:White;
}
I need to force the full collapse of the open accordions depending on which new accordion is selected. If an internal accordion is selected then I only want the other internal accordions to close. If an external accordion is selected I want the internal and external accordions to close.
Closing means assigning the 'collapsed' class to the accordion-toggle, which determines the highlight colour of the accordion-heading.
I have the following javascript which needs amending to select the different levels of accordion. The class of 'outcome' for External and 'achievement' for internal are currently the only difference between the two.
I've tried a variety of if/else combinations but none of them seem to work. I've included the javascript I use when changing tabs as this might change how I need to approach this.
<script type="text/javascript">
//need to collapse all when tab changes
$('a[data-toggle="tab"]').on('shown', function (e) {
$('.accordion').find('.accordion-toggle').addClass('collapsed');
$('.accordion').find('.accordion-body').removeClass('in');
$('.accordion').find('.accordion-body').height('0px');
}
);
//collapse accordion depending on class
// from https://github.com/twbs/bootstrap/issues/7213#issuecomment-18547519
$('.collapse').on('hide', function () {
//do something to select internal or external accordion here...
$('[href="#' + $(this).attr('id') + '"]').addClass('collapsed');
});
</script>
The HTML for the above accordion set is as follows:
<div class="accordion" id="interventions">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle outcome collapsed" data-toggle="collapse" data-parent="#interventions" href="#collapse12">
<label for="">Test Finance</label>
</a>
</div>
<div id="collapse12" class="accordion-body collapse">
<div class="accordion" id="intervention0">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle achievement" data-toggle="collapse" data-parent="#intervention0" href="#collapse012">
<label for="">Achievement Finance 3</label>
</a>
</div>
<div id="collapse012" class="accordion-body collapse">
<div class="accordion-inner">
<div class="accordion-group">Test group</div>
</div>
</div>
</div>
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle achievement" data-toggle="collapse" data-parent="#intervention0" href="#collapse111">
<label for="">Achievement Finance 2</label>
</a>
</div>
<div id="collapse111" class="accordion-body collapse">
<div class="accordion-inner">
<div class="accordion-group">Test group</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle outcome collapsed" data-toggle="collapse" data-parent="#interventions" href="#collapse10">
<label for="">Huge Money</label>
</a>
</div>
<div id="collapse10" class="accordion-body collapse">
<div class="accordion" id="intervention1">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle achievement" data-toggle="collapse" data-parent="#intervention1" href="#collapse010">
<label for="">Achievement Finance 1</label>
</a>
</div>
<div id="collapse010" class="accordion-body collapse">
<div class="accordion-inner">
<div class="accordion-group">Test group</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
I managed to sort this out using the following javascript. The custom classes are only used by the CSS to apply the correct colour to an accordion-toggle when it is open or collapsed.
The css is amended to:
.accordion-toggle.outcome {
background-color:#d9edf7;
}
.accordion-toggle.achievement {
background-color:#dff0d8;
}
.accordion-toggle.collapsed {
background-color:transparent;
}
Thanks to Ammu for helping with this related question.
Javascript
//function to collapse all accordions when changing tabs
function tabCollapse() {
$('.accordion').find('.accordion-toggle').addClass('collapsed');
$('.accordion').find('.accordion-body').removeClass('in');
$('.accordion').find('.accordion-body').height('0px');
}
//function to fully collapse accordion on same page
function pageCollapse(inner) {
$('#' + inner).find('.accordion-toggle').addClass('collapsed');
$('#' + inner).find('.accordion-body').removeClass('in');
$('#' + inner).find('.accordion-body').height('0px');
}
//collapse all when tab changes
$('a[data-toggle="tab"]').on('shown', function () {
tabCollapse();
});
//collapse inner accordion on same page
$('.accordion').on('hidden', function (e) {
var inner = e.target.id;
pageCollapse(inner);
});
//on hide remove colour
$('.accordion').on('hide', function (e) {
var selected = e.target.id;
$('#' + selected).siblings().find('.accordion-toggle').addClass('collapsed');
});

Categories