I currently have a significant amount of HTML inside a div which is generated within an iteration from a GET request to my .net core server.
Some of the values in the HTML is dynamic data returned from the server.
I've added a button to my website, which when pressed, makes an AJAX call to the server to return a JSON object representing the dynamic values for the next iteration.
So, I would like the JavaScript to add a new div to the DOM, which is the same, and has my dynamic values populated based on the JSON response.
For context, the DIV looks like this (which is from a bootstrap template I purchased):
<div >
<!-- Card header START -->
<div >
<div >
<div >
<!-- Avatar -->
<div >
<a href="#!"> <img src="@post.ProfileImageUrl" alt="profile picture"> </a>
</div>
<!-- Info -->
<div>
<div >
<h6 > <a href="#!"> @post.ProfileName </a></h6>
<span > @post.PostTime</span>
</div>
</div>
</div>
<!-- Card feed action dropdown START -->
<div >
<a href="#" id="cardFeedAction" data-bs-toggle="dropdown" aria-expanded="false">
<i ></i>
</a>
<!-- Card feed action dropdown menu -->
<ul aria-labelledby="cardFeedAction">
<li><a href="#"> <i ></i>Save post</a></li>
<li><a href="#"> <i ></i>Unfollow lori ferguson </a></li>
<li><a href="#"> <i ></i>Hide post</a></li>
<li><a href="#"> <i ></i>Block</a></li>
<li><hr ></li>
<li><a href="#"> <i ></i>Report post</a></li>
</ul>
</div>
<!-- Card feed action dropdown END -->
</div>
</div>
<!-- Card header END -->
<!-- Card body START -->
<div >
<p><strong>@post.PostBody</strong></p>
<!-- Card img -->
<img src="@post.PostImageUrl" alt="Post">
<!-- Feed react START -->
<ul >
<li >
<a href="#!"> <i ></i>Liked (56)</a>
</li>
<li >
<a href="#!"> <i ></i>Comments (12)</a>
</li>
<!-- Card share action START -->
<li >
<a href="#" id="cardShareAction" data-bs-toggle="dropdown" aria-expanded="false">
<i ></i>Share (3)
</a>
<!-- Card share action dropdown menu -->
<ul aria-labelledby="cardShareAction">
<li><a href="#"> <i ></i>Send via Direct Message</a></li>
<li><a href="#"> <i ></i>Bookmark </a></li>
<li><a href="#"> <i ></i>Copy link to post</a></li>
<li><a href="#"> <i ></i>Share post via …</a></li>
<li><hr ></li>
<li><a href="#"> <i ></i>Share to News Feed</a></li>
</ul>
</li>
<!-- Card share action END -->
</ul>
</div>
<!-- Card body END -->
<!-- Card footer START -->
<div >
<!-- Load more comments -->
<a href="#!" role="button" data-bs-toggle="button" aria-pressed="true">
<div >
<span ></span>
<span ></span>
<span ></span>
</div>
Load more comments
</a>
</div>
<!-- Card footer END -->
</div>
<!-- Card feed item END -->
Question:
There's a lot of HTML here. What's the best way to build this out in Javascript? Is it just a case of biting the bullet and writing all of the JS code to create each element/class?
Would this be the best practice? Because it effectively means I'm maintaining the HTML markup in two places..
Thank you..!
CodePudding user response:
I usually save the html of the template to be rendered inside an hidden element. Then I can always access it using that element.innerHTML
. You could use specialized script
tag instead. But the innerHTML
part is the same.
After having the HTML as string you have 2 options
- build the string with the values you want to populate, then add that as
innerHTML
to the target container. - but a better approach is to create an element from that
html
(see function below) then append it and manipulate it otherwise.
// render 5 cards
for (var i = 0; i < 5; i ) {
var html = document.querySelector("#card-template").innerHTML;
var elem = elemFromString(html)
// change something
elem.querySelector(".card-body>p strong").innerText = "card " i
// append
document.querySelector("#container").append(elem)
}
// usefull utility
function elemFromString(html) {
var dummy = document.createElement("div");
dummy.innerHTML = html.trim();
if (dummy.children.length > 1) {
console.error("expecting one wrapping element for html. will return only firstChild")
}
var result = dummy.firstChild;
result.parentNode.removeChild(result)
return result;
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI N" crossorigin="anonymous">
<div id="container">
</div>
<div id="card-template" style="display:none">
<div >
<!-- Card header START -->
<div >
<div >
<div >
<!-- Avatar -->
<div >
<a href="#!"> <img src="@post.ProfileImageUrl" alt="profile picture"> </a>
</div>
<!-- Info -->
<div>
<div >
<h6 > <a href="#!"> @post.ProfileName </a></h6>
<span > @post.PostTime</span>
</div>
</div>
</div>
<!-- Card feed action dropdown START -->
<div >
<a href="#" id="cardFeedAction" data-bs-toggle="dropdown" aria-expanded="false">
<i ></i>
</a>
<!-- Card feed action dropdown menu -->
<ul aria-labelledby="cardFeedAction">
<li>
<a href="#"> <i ></i>Save post</a>
</li>
<li>
<a href="#"> <i ></i>Unfollow lori ferguson </a>
</li>
<li>
<a href="#"> <i ></i>Hide post</a>
</li>
<li>
<a href="#"> <i ></i>Block</a>
</li>
<li>
<hr >
</li>
<li>
<a href="#"> <i ></i>Report post</a>
</li>
</ul>
</div>
<!-- Card feed action dropdown END -->
</div>
</div>
<!-- Card header END -->
<!-- Card body START -->
<div >
<p><strong>@post.PostBody</strong></p>
<!-- Card img -->
<img src="@post.PostImageUrl" alt="Post">
<!-- Feed react START -->
<ul >
<li >
<a href="#!"> <i ></i>Liked (56)</a>
</li>
<li >
<a href="#!"> <i ></i>Comments (12)</a>
</li>
<!-- Card share action START -->
<li >
<a href="#" id="cardShareAction" data-bs-toggle="dropdown" aria-expanded="false">
<i ></i>Share (3)
</a>
<!-- Card share action dropdown menu -->
<ul aria-labelledby="cardShareAction">
<li>
<a href="#"> <i ></i>Send via Direct Message</a>
</li>
<li>
<a href="#"> <i ></i>Bookmark </a>
</li>
<li>
<a href="#"> <i ></i>Copy link to post</a>
</li>
<li>
<a href="#"> <i ></i>Share post via …</a>
</li>
<li>
<hr >
</li>
<li>
<a href="#"> <i ></i>Share to News Feed</a>
</li>
</ul>
</li>
<!-- Card share action END -->
</ul>
</div>
<!-- Card body END -->
<!-- Card footer START -->
<div >
<!-- Load more comments -->
<a href="#!" role="button" data-bs-toggle="button" aria-pressed="true">
<div >
<span ></span>
<span ></span>
<span ></span>
</div>
Load more comments
</a>
</div>
<!-- Card footer END -->
</div>
<!-- Card feed item END -->
</div>