Note that I have employed jQuery here for the ease of selecting the element & inserting and because Bootstrap — which you are using — uses jQuery anyways. You can easily do this with pure JS via document.getElementById(...) as well.
You can use a function to repeat how many times you want to duplicate your element, in the following snippet I created a function that will clone .card node using .cloneNode() and iterate a number of times, then modify the ids and attributes using querySelector() on the cloned node, here is a snippet for option A:
function duplicateElement(selector, numOfDuplicates) {
let element = document.querySelector(selector);
for(let i = numOfDuplicates; i > 0; i--) {
let newElement = element.cloneNode(true);
newElement.querySelector('#headingOne').id = `headingOne-${i}`;
newElement.querySelector('#collapseOne').id = `collapseOne-${i}`;
newElement.querySelector('#collapseTwo').id = `collapseTwo-${i}`;
newElement.querySelector('#headingTwo').id = `headingTwo-${i}`;
let toggleBtn = newElement.querySelector('[data-target="#collapseOne"]');
toggleBtn.dataset['target'] = `#collapseOne-${i}`;
toggleBtn.setAttribute('aria-controls', `collapseOne-${i}`);
let toggleBtn2 = newElement.querySelector('[data-target="#collapseTwo"]');
toggleBtn2.dataset['target'] = `#collapseTwo-${i}`;
toggleBtn2.setAttribute('aria-controls', `collapseTwo-${i}`);
element.after(newElement);
}
}
duplicateElement('.card', 4);
If you are looking for option C solution, it will be a bit complicated if your project is not already using React or other client rendering library or front-end framework, you have to use Webpack with Babel to setup the front-end framework and code-base for your project, here is a working codesandbox sample for on how you might implement your bootstrap front-end using React.
In the following snippet, I created a component function and used Array.map() on array [1, 2, 3, 4, 5] to create 5 components:
import React, { useState } from "react";
import { Collapse, Button, Card } from "react-bootstrap";
import "bootstrap/dist/css/bootstrap.min.css";
import "./styles.css";
function Example() {
const [open, setOpen] = useState(false);
const [openLevel, setOpenLevel] = useState(false);
return (
<>
<Card>
<Card.Header>
<Button
onClick={() => setOpen(!open)}
aria-controls="collapseOne"
aria-expanded={open}
>
Collapsible Group Item #1
</Button>
</Card.Header>
<Collapse className="first-coll" in={open}>
<Card.Body id="collapseOne">
<Card>
<Card.Header>
<Button
onClick={() => setOpenLevel(!openLevel)}
aria-controls="collapseTwo"
aria-expanded={openLevel}
>
Collapsible Group Item #2
</Button>
</Card.Header>
<Collapse className="second-coll" in={openLevel}>
<Card.Body id="collapseTwo">
Anim pariatur cliche reprehenderit, enim eiusmod high life
accusamus wolf moon put a craft beer sapiente ea proident. Ad
vegan excepteur butcher vice lomo. Leggings farm-
</Card.Body>
</Collapse>
</Card>
</Card.Body>
</Collapse>
</Card>
</>
);
}
export default function App() {
return (
<div className="App">
{[1, 2, 3, 4, 5].map((el, i) => {
return <Example key={i} />;
})}
</div>
);
}
Solution 3 :
I reckon I have found another answer, it involves the html <template> tag and json to get the data.
The HTML Content Template (<template>) element is a mechanism for holding HTML that is not to be rendered immediately when a page is loaded but may be instantiated subsequently during runtime using JavaScript.
Thus it is exactly what you need for this kind of problem.
Solution
First of all, you need to specify the button text and the card-content in a json object. This json can reside in a separate file (and loaded as seen below) or you can place the json content inside a variable as seen in the jsfiddle.
1. Using a Json file
data.json
[
{
"button" : "Button 1",
"body" : "Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt"
},
{
"button" : "Button 2",
"body" : "aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat"
},
{
"button" : "Button 3",
"body" : "craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS."
},
{
"button" : "Button 4",
"body" : "Lorem ipsum dolor sit amet"
}
]
loadDom function:
function loadDom() {
//Get the data from data.json
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'data.json', true);
xobj.onreadystatechange = function() {
if (xobj.readyState == 4 && xobj.status == "200") {
//parse the json
let dataToLoad = JSON.parse(xobj.responseText);
//create the cards
dataToLoad.forEach((card, i) => {
createCard(i, card["button"], card["body"]);
});
}
};
xobj.send(null);
}
2. Inline Json
function loadDom() {
//Just specify the data that you want...
var dataToLoad = [{
"button": "Button 1",
"body": "Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt"
},
{
"button": "Button 2",
"body": "aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat"
},
{
"button": "Button 3",
"body": "craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS."
},
{
"button": "Button 4",
"body": "Lorem ipsum dolor sit amet"
}
];
//load the data from json and create the cards
dataToLoad.forEach((card, i) => {
createCard(i, card["button"], card["body"]);
});
}
function createCard(id, buttonText, cardBody) {
var card = document.getElementById("cardTemplate").content;
//clone the card template
var cln = card.cloneNode(true);
//create the custom heading and collapse id
let headingId = "heading-" + id;
let collapseId = "collapse-" + id;
//set all the attributes
cln.querySelectorAll(".card-header")[0].id = headingId;
cln.querySelectorAll(".card-header button")[0].setAttribute("data-target", "#" + collapseId);
cln.querySelectorAll(".card-header button")[0].setAttribute("aria-controls", collapseId);
cln.querySelectorAll(".card-body")[0].parentElement.id = collapseId;
cln.querySelectorAll(".card-body")[0].parentElement.setAttribute("aria-labelledby", headingId);
//set the content
cln.querySelectorAll(".card-header button")[0].innerHTML = buttonText;
cln.querySelectorAll(".card-body")[0].innerHTML = cardBody;
//add the card to the accordion
document.getElementById("accordion").appendChild(cln);
}
(For this example I borrowed @Polygnome’s <head> code)
Solution 4 :
As an extension of Polygnome’s answer,
You can accomplish this in vanilla JavaScript using the following:
function appendCard(id, content) {
let el = document.querySelector(".card");
let content = document.createTextNode(`<div class="card">
<div class="card-header" id="heading-${id}">
<h5 class="mb-0">
<button class="btn btn-link collapsed" data-toggle="collapse" data-target="#collapse-${id}" aria-expanded="false" aria-controls="collapse-${id}">Collapsible Group Item #${id}</button>
</h5>
</div>
<div id="collapse-${id}" class="collapse" aria-labelledby="heading-${id}">
<div class="card-body">
${content}
</div>
</div>
</div>`);
el.appendChild(content);
}
Hope this helps!
Solution 5 :
answer to A– There’s no way out with pure HTML and CSS, As HTML is the language where you define the content, that’s why you have to repeat the same things ‘n’ times for ‘n’ number of results… But if you feel confused while giving each repeated content a new class and Id for its unique CSS, Then it is not required, as you can simply use :nth-child() property… You can just copy and paste the code in HTML with same classes and still you can define different CSS to each one of them… CHECK:nth-child() for more info !!
answer to B and C– Well, there is not much left that I can sill tell you now, as I am a bit late to the party and the answers have already been discussed by others, which I feel are absolutely correct and relatable… You can kindly check other answers from different users (like- Chiel, ROOT, Polygnome & Coder100) for desired results with the use of different languages and frameworks outside pure CSS and HTML…
Have a nice day to everyone!!
Regards,
Om Chaudhary
Problem :
<div class="card" style>
<div class="card-header" id="headingOne">
<h5 class="mb-0">
<button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" aria-
expanded="true" aria-controls="collapseOne">
Collapsible Group Item #1
</button>
</h5>
</div>
<!-- Add mx-auto -->
<div id="collapseOne" class="collapse show text-center mx-auto" aria-labelledby="headingOne"
style="width:300px;">
<div class="card-body">
<div class="card">
<div class="card-header text-center" id="headingTwo" style="width:300px;">
<h5 class="mb-0">
<button class="btn btn-link collapsed text-center" data- toggle="collapse" data-
target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo" style="width:300px;">
Collapsible Group Item #2
</button>
</h5>
</div>
<div id="collapseTwo" class="collapse show" aria-labelledby="headingTwo">
<div class="card-body">
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus wolf moon put a
craft beer sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings farm-
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header" id="headingThree">
<h5 class="mb-0">
<button class="btn btn-link collapsed" data-toggle="collapse" data- target="#collapseThree"
aria-expanded="false" aria-controls="collapseThree">
Collapsible Group Item #3
</button>
</h5>
</div>
<div id="collapseThree" class="collapse" aria-labelledby="headingThree">
<div class="card-body">
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry wolf moon
et. Nihil anim keffiyeh helvetica, craft beer labore wes sapiente ea proident. Ad vegan
</div>
</div>
</div>
</div>
Hello I have been copying and pasting this like 10-20 times on my code changing the id the header id and the button. I also had been copying and pasting a bunch of other html code (image tag about 20 images) I was wondering if there was a way to stop repeating code (like a function) with pure html css. If not can you do it with plain vanilla js? if not then what are the other ways?
In short
Most important question (A is most important C is least)
A) is there a way to prevent repeating code with the collapse code
above with just pure HTML/CSS? if yes how?
B) is there a way to prevent repeating code with the collapse code
above with just pure HTML/CSS/vanilla js? if yes how?
C) is there a way to prevent repeating code with the collapse code
above with just pure HTML/CSS/angular/react? if yes how?
Comments
Comment posted by B001ᛦ
Templates might be a good friend
Comment posted by stackoverflow.com/questions/35617964/…
it can absolutely be done with vanilla. you will have to select the parent element and do for loop on innerHTML for each thing you need. See this other answer where a table is built. Should get you started.
Comment posted by is not exactly a helpful answer
@B001ᛦ Telling someone to use Google
Comment posted by dragonn
@Goofballtech thanks. So you need js right? there’s not way to do it with pure html or css?
Comment posted by Goofballtech
i have never found myself not having javascript to use so i honestly don’t know. My best answer….. “maybe?”. I know vanilla can do ot for sure though…
Comment posted by Polygnome
If you lift code from other answers, at least give credit.