简体   繁体   中英

Generating dynamic html cards from a javascript array

I would like to display some card elements in HTML. I would like to get the variables of the card element from a javascript array.(Such as title etc..). The card element number will also depend on the Javascript array size. I have looked at other questions such as generating dynamic tables but as I have a long customized html code block, it doesn't work.

This is for a website that I am building. I already got the variables from an api end point with a HTTP get request but am unable to display as I wish to. I have looked at many similar questions but can't find the answer that I am looking for.

This is the script for getting the variables with the HTTP get request

<script>
const request = new XMLHttpRequest();

request.open('GET', 'api/seminars', true);
request.onload = function() {
  // Begin accessing JSON data here
  const data = JSON.parse(this.response);

  if (request.status >= 200 && request.status < 400) {
    data.forEach(resultArray => {
      document.getElementById('output').innerHTML = resultArray.name;
      document.getElementById('description').innerHTML =
        resultArray.description;
      document.getElementById('date').innerHTML = resultArray.date;
    });
  } else {
    console.log('error');
  }
};

request.send();
</script>

HTML CODE :

<div id="accordion">
    <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">

                </button>
            </h5>
        </div>

        <div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordion">
            <div class="card-body">

                <h5 id="name"></h5>
                <p id="description"></p>
                <p id="description"></p>
                ...
            </div>
        </div>
    </div>
</div>

And I have continued html code from here on not relevant ..

If there are 3 objects in my array, I would like to create 3 different cards and display name,description.. attributes. But my code only creates one card and displays last object's attributes.

You code never really "creates" elements based on your API call - It just updates (ie, overwrites) the existing dom elements by updating the innerHTML of fixed elements referenced by their IDs.

If my interpretation of your code is correct, you should be only seeing the LAST item in your API result. There are also some other weird stuff going on like duplicate IDs which Im guessing are typos

To fix this, create a new div.card-body for each item your API returns and append it to your container

 const apiResult = [{ title: "title1", description: "desc1", output: "out1" }, { title: "title2", description: "desc2", output: "out2" }, { title: "title3", description: "desc3", output: "out3" }]; const container = document.getElementById('accordion'); apiResult.forEach((result, idx) => { // Create card element const card = document.createElement('div'); card.classList = 'card-body'; // Construct card content const content = ` <div class="card"> <div class="card-header" id="heading-${idx}"> <h5 class="mb-0"> <button class="btn btn-link" data-toggle="collapse" data-target="#collapse-${idx}" aria-expanded="true" aria-controls="collapse-${idx}"> </button> </h5> </div> <div id="collapse-${idx}" class="collapse show" aria-labelledby="heading-${idx}" data-parent="#accordion"> <div class="card-body"> <h5>${result.title}</h5> <p>${result.description}</p> <p>${result.output}</p> ... </div> </div> </div> `; // Append newyly created card element to the container container.innerHTML += content; }) 
 .card { padding: 1rem; border: 1px solid black; margin: 1rem; } 
 <div id="accordion"> </div> 

Note:

While this works, it's not very scalable. There are some great templating libraries out there with much more advanced interpolation features that you can consider if you have to do something like this in many places (and maintain it)

jsRender

Underscore Templates

Handlebars

UI frameworks like Vue , React , Angular wrap templating with binding to data models and handle auto updating the DOM for you to make things like this easier. Worth investigating if you have a lot of dynamically updating parts on your webpage

You are overwriting the description's innerHTML with every repetition of your for loop .

Change this

 document.getElementById('output').innerHTML = resultArray.name; document.getElementById('description').innerHTML = resultArray.description; document.getElementById('date').innerHTML = resultArray.date; 

to this

 var element = document.createElement('div'); // create new div var name = document.createElement('h4'); name.innerHTML = resultArray.name; element.appendChild(name); var description = document.createElement('p'); description.innerHTML = resultArray.description; element.appendChild(description); var date = document.createElement('span'); date.innerHTML = resultArray.date; element.appendChild(date); document.body.appendChild(element); 

Suppose you have already queried the API, a way of doing it could be:

 // Supposing you already have queried the API and have your data let data = [ {name: 'name0', description: 'description', date: 'XX/XX/XXXX'}, {name: 'name1', description: 'description', date: 'XX/XX/XXXX'}, {name: 'name2', description: 'description', date: 'XX/XX/XXXX'}, ] data.forEach(res => { let card = document.createElement("div"); let name = document.createTextNode('Name:' + res.name + ', '); card.appendChild(name); let description = document.createTextNode('Description:' + res.description + ', '); card.appendChild(description); let date = document.createTextNode('date:' + res.date); card.appendChild(date); let container = document.querySelector("#container"); container.appendChild(card); }); 
 <!-- At one point where you want to generate the cards you put this container --> <div id="container"></div> 

Yours was not working since you updated always the same elements instead of appending new ones :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM