javascript - is there a way to prevent repeating code in html I'm using bootstrap 4 collapse like 20 times in one page -

<div class="card" style><div class="card-header" id="headingOne"&

    <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?
    <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?
Share Improve this question edited Jun 17, 2020 at 11:52 Chiel 1,4621 gold badge13 silver badges33 bronze badges asked Jun 14, 2020 at 16:29 dragonndragonn 3311 gold badge6 silver badges23 bronze badges 8
  • Templates might be a good friend – B001ᛦ Commented Jun 14, 2020 at 16:30
  • 1 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. stackoverflow./questions/35617964/… – Goofballtech Commented Jun 14, 2020 at 16:34
  • 1 @B001ᛦ Telling someone to use Google is not exactly a helpful answer – pafau k. Commented Jun 14, 2020 at 16:36
  • 1 @Goofballtech thanks. So you need js right? there's not way to do it with pure html or css? – dragonn Commented Jun 14, 2020 at 16:37
  • 1 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... – Goofballtech Commented Jun 14, 2020 at 16:41
 |  Show 3 more ments

5 Answers 5

Reset to default 3

I reckon I have found another answer, it involves the html <template> tag and json to get the data.

html template

As mdn states it :

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);
}
<!DOCTYPE html>
<html lang="en" dir="ltr">

<head>
  <meta charset="utf-8">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <link rel="stylesheet" href="https://stackpath.bootstrapcdn./bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
  <script src="https://code.jquery./jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn./bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>

</head>

<body onload="loadDom();">
  <div id="accordion">
    <template id="cardTemplate">
      <!-- Card -->
      <div class="card">
        <div class="card-header">
          <h5 class="mb-0">
            <button class="btn btn-link" data-toggle="collapse" aria-expanded="true" >
            </button>
          </h5>
        </div>

        <div class="collapse" data-parent="#accordion">
          <div class="card-body">

        </div>
      </div>
    </div>
    <!-- /card -->
  </template>


  </div>
</body>

</html>

Hope this helps! If not, please ment

(For this example I borrowed @Polygnome's <head> code)

In pure HTML/CSS this isn't possible, unless you employ a server-side rendering with some template language.

As far as doing it with pure HTML/CSS/JS, ECMAScript 262 introduced template literals which can be employed to great effectiveness here:

<script>
    function createCard(id, content) {
        return `<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>`;
    }
    $(function(){
        // create one card
        $('#cards').append($(createCard('1', "Lorem ipsum")));
        // create nested cards
        $('#cards').append($(createCard('2', createCard(3, "Dolor sit amnet"))));
    });
</script>

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.

A working demo can be seen here:

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn./bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">

    <title>Hello, world!</title>
  </head>
  <body>
    <h1>Hello, world!</h1>
    
    <div class="container" id="cards">
    </div>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery./jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn./bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
    
    <script>
        function createCard(id, content) {
            return `<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>`;
        }
        $(function(){
            $('#cards').append($(createCard('1', "Lorem ipsum")));
            $('#cards').append($(createCard('2', createCard(3, "Dolor sit amnet"))));
        });
    </script>
  </body>
</html>

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);
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn./bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://code.jquery./jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn./bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>


<div class="card">
    <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>

If you are looking for option C solution, it will be a bit plicated 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 ponent function and used Array.map() on array [1, 2, 3, 4, 5] to create 5 ponents:

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>
  );
}

As an extension of Polygnome's answer,

You can acplish 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!

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

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744189007a4562342.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信