6
\$\begingroup\$

I have the following code which inserts a new element of the same type over and over again to the parent element. I am new to JavaScript so was wondering if there was a better way of doing this. I apologise for the variable names, I'll get around to changing those later, just allows me to see the flow better. I'm trying to write this in pure js.

//Add a new lobby element
document.getElementById("addLobby").addEventListener("click", function(e) {
  var layer1 = document.createElement("div");
  layer1.setAttribute("class","col-wd-12 col-md-6 col-sm-4");
  var layer2 = document.createElement("div");
  layer2.setAttribute("class","col lobby");
  var layer3 = document.createElement("div");
  layer3.setAttribute("class","col lobby-infoPanel");
  var layer3v2 = document.createElement("div");
  layer3v2.setAttribute("class","overlay lobby-overlay");
  var layer3v2v1 = document.createElement("a");
  layer3v2v1.setAttribute("href","#");
  var l3v2v1v1 = document.createElement("span");
  l3v2v1v1.setAttribute("class", "overlay-options lobby-overlay-options");
  var layer4 = document.createElement("div");
  layer4.setAttribute("class","col lobby-info-count");
  var layer4v2 = document.createElement("div");
  layer4v2.setAttribute("class","col lobby-info-count lobby-info-users");

  var l3v2v1v1Text = document.createTextNode("+");
  var l4text = document.createTextNode("5/5");
  var l4v2text = document.createTextNode("@User1");

  layer4v2.appendChild(l4v2text);
  layer4.appendChild(l4text);
  layer3.appendChild(layer4);
  layer3.appendChild(layer4v2);
  l3v2v1v1.appendChild(l3v2v1v1Text);
  layer3v2v1.appendChild(l3v2v1v1);
  layer3v2.appendChild(layer3v2v1);
  layer2.appendChild(layer3);
  layer2.appendChild(layer3v2);
  layer1.appendChild(layer2);

  var lastNode = document.getElementById("addLobby").parentElement;
  lastNode.parentElement.insertBefore(layer1, lastNode);
});
\$\endgroup\$
  • 1
    \$\begingroup\$ Try a loop. They are great and do all things. \$\endgroup\$ – Riker Mar 31 '16 at 17:39
4
\$\begingroup\$

First suggestion

One first refactoring idea is to create a function that creates an element, sets its attributes and adds it to a parent element.

function createElement(elementType, classes, parent) {
    var e = document.createElement(e);
    e.setAttribute('class', classes);
    parent.appendChild(e);
    return e;
}

You could also separate your structure from your DOM manipulation. I suggest you create your structure as a JSON, and then create the nodes recursively.

For example, you could define your structure as:

{
  element: 'div',
  class: 'col-wd-12 col-md-6 col-sm-4',
  children: [{
    element: 'div',
    class: 'col loby',
    children: [
      //...
    ]
  },
  // ...
}

and then:

function createDOMElements(data) {
  // ...

  // create the element
  var elem = document.createElement(data.element);

  // add its attributes
  for (var attribute in data) {
    if (data.hasOwnProperty(attribute) && attribute !== 'element' && attribute !== 'children') {
      var attributeValue = data[attribute];
      elem.setAttribute(attribute, attributeValue);
    }
  }
  // ...

  // add the children (forEach is from ES5 on)
  data.children.forEach(function(child) {
    // recursive call to create child elements
    var childElement = createDOMElements(child);
    elem.appendChild(childElement);
  });

  return elem;
}

Here is a jsfiddle with the whole working example.

Second suggestion (less JS)

You could create a hidden HTML 'template' and display it when needed.

You can set:

  • visibility to hidden if you still want to affect the layout (take the space needed)

  • or display to none

in css (more info here) directly in the style attribute or through a class. On the click event you make this element visible.

The HTML:

  <div id="template" class="col-wd-12 col-md-6 col-sm-4" style="display:none;">
      <!-- all the children -->
  </div>

And then in the JS:

document.getElementById("addLobby").addEventListener("click", function(e) {
  document.getElementById("template").style.display = "initial";
});

Here is the second fiddle.

If you need to add the template multiple times, or if you have multiple templates on your page, you should define them at the end on the page. When needed, clone the template and append it to the desired parent.

Conclusion

If you don't have a particular need to create the elements in the JS, I think the second solution it's more elegant (and less code ;) )

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.