Search code examples
javascriptjsonapi-design

Using Javascript loop to create multiple HTML elements


I would like to use a javascript loop to create multiple HTML wrapper elements and insert JSON response API data into some of the elements (image, title, url, etc...).

Is this something I need to go line-by-line with?

<a class="scoreboard-video-outer-link" href="">
  <div class="scoreboard-video--wrapper">
    <div class="scoreboard-video--thumbnail">
      <img src="http://via.placeholder.com/350x150">
    </div>
    <div class="scoreboard-video--info">
      <div class="scoreboard-video--title">Pelicans @ Bulls Postgame: E'Twaun Moore 10-8-17</div>
    </div>
  </div>
</a>

What I am trying:

var link = document.createElement('a');
document.getElementsByTagName("a")[0].setAttribute("class", "scoreboard-video-outer-link");
document.getElementsByTagName("a")[0].setAttribute("url", "google.com"); 
mainWrapper.appendChild(link);

var videoWrapper= document.createElement('div');
document.getElementsByTagName("div")[0].setAttribute("class", "scoreboard-video-outer-link");
link.appendChild(videoWrapper);

var videoThumbnailWrapper = document.createElement('div');
document.getElementsByTagName("div")[0].setAttribute("class", "scoreboard-video--thumbnail");
 videoWrapper.appendChild(videoThumbnailWrapper);

var videoImage = document.createElement('img');
document.getElementsByTagName("img")[0].setAttribute("src", "url-of-image-from-api");
videoThumbnailWrapper.appendChild(videoImage);

Then I basically repeat that process for all nested HTML elements.

  • Create A-tag
  • Create class and href attributes for A-tag
  • Append class name and url to attributes
  • Append A-tag to main wrapper

  • Create DIV

  • Create class attributes for DIV
  • Append DIV to newly appended A-tag

I'd greatly appreciate it if you could enlighten me on the best way to do what I'm trying to explain here? Seems like it would get very messy.


Solution

  • Here's my answer. It's notated. In order to see the effects in the snippet you'll have to go into your developers console to either inspect the wrapper element or look at your developers console log.

    We basically create some helper methods to easily create elements and append them to the DOM - it's really not as hard as it seems. This should also leave you in an easy place to append JSON retrieved Objects as properties to your elements!

    Here's a Basic Version to give you the gist of what's happening and how to use it

    //create element function
    
    function create(tagName, props) {
      return Object.assign(document.createElement(tagName), (props || {}));
    }
    
    //append child function
    
    function ac(p, c) {
      if (c) p.appendChild(c);
      return p;
    }
    
    //example: 
    //get wrapper div
    let mainWrapper = document.getElementById("mainWrapper");
    
    //create link and div
    let link = create("a", { href:"google.com" });
    let div = create("div", { id: "myDiv" });
    
    //add link as a child to div, add the result to mainWrapper
    ac(mainWrapper, ac(div, link));
    

    //create element function
    
    function create(tagName, props) {
      return Object.assign(document.createElement(tagName), (props || {}));
    }
    
    //append child function
    
    function ac(p, c) {
      if (c) p.appendChild(c);
      return p;
    }
    
    //example: 
    //get wrapper div
    let mainWrapper = document.getElementById("mainWrapper");
    
    //create link and div
    let link = create("a", { href:"google.com", textContent: "this text is a Link in the div" });
    let div = create("div", { id: "myDiv", textContent: "this text is in the div! " });
    
    //add link as a child to div, add the result to mainWrapper
    ac(mainWrapper, ac(div, link));
    div {
    border: 3px solid black;
    padding: 5px;
    
    }
    <div id="mainWrapper"></div>

    Here is how to do specifically what you asked with more thoroughly notated code.

    //get main wrapper
    let mainWrapper = document.getElementById("mainWrapper");
    
    //make a function to easily create elements
    //function takes a tagName and an optional object for property values
    //using Object.assign we can make tailored elements quickly.
    
    function create(tagName, props) {
      return Object.assign(document.createElement(tagName), (props || {}));
    }
    
    
    //document.appendChild is great except 
    //it doesn't offer easy stackability
    //The reason for this is that it always returns the appended child element
    //we create a function that appends from Parent to Child 
    //and returns the compiled element(The Parent).
    //Since we are ALWAYS returning the parent(regardles of if the child is specified) 
    //we can recursively call this function to great effect
    //(you'll see this further down)
    function ac(p, c) {
      if (c) p.appendChild(c);
      return p;
    }
    
    //these are the elements you wanted to append
    //notice how easy it is to make them!
    
    //FYI when adding classes directly to an HTMLElement
    //the property to assign a value to is className  -- NOT class
    //this is a common mistake, so no big deal!
    
    var link = create("a", {
      className: "scoreboard-video-outer-link",
      url: "google.com"
    });
    
    var videoWrapper = create("div", {
      className: "scoreboard-video-outer-link"
    });
    
    var videoThumbnailWrapper = create("div", {
      className: "scoreboard-video--thumbnail"
    });
    
    var videoImage = create("img", {
      src: "url-of-image-from-api"
    });
    
    //here's where the recursion comes in:
    ac(mainWrapper, ac(link, ac(videoWrapper, ac(videoThumbnailWrapper, videoImage))));
    
    //keep in mind that it might be easiest to read the ac functions backwards
    //the logic is this:
    
    //Append videoImage to videoThumbnailWrapper
    //Append (videoImage+videoThumbnailWrapper) to videoWrapper 
    //Append (videoWrapper+videoImage+videoThumbnailWrapper) to link
    //Append (link+videoWrapper+videoImage+videoThumbnailWrapper) to mainWrapper
    

    let mainWrapper = document.getElementById('mainWrapper');
    
    function create(tagName, props) {
      return Object.assign(document.createElement(tagName), (props || {}));
    }
    
    function ac(p, c) {
      if (c) p.appendChild(c);
      return p;
    }
    
    var link = create("a", {
      className: "scoreboard-video-outer-link",
      url: "google.com"
    });
    
    var videoWrapper = create("div", {
      className: "scoreboard-video-outer-link"
    });
    
    var videoThumbnailWrapper = create("div", {
      className: "scoreboard-video--thumbnail"
    });
    
    
    
    var videoImage = create("img", {
      src: "url-of-image-from-api"
    });
    
    ac(mainWrapper, ac(link, ac(videoWrapper, ac(videoThumbnailWrapper, videoImage))));
    //pretty fancy.
    //This is just to show the output in the log,
    //feel free to just open up the developer console and look at the mainWrapper element.
    
    console.dir(mainWrapper);
    <div id="mainWrapper"></div>