1

OK so I'm appending HTML elements to the DOM with this following javascript..

$h.each(domNodes, function(domNode) {
  var input;
    input = document.createElement('input');
    input.setAttribute('type', 'file');
    input.setAttribute('id', 'image-file');
    input.setAttribute('name', 'files[]');
    input.style.display = 'none';
    domNode.addEventListener('click', function(){
      input.style.opacity = 0;
      input.style.display='block';
      input.focus();
      input.click();
      input.style.display='none';
    }, false);
    domNode.appendChild(input);
  }
}

And this creates a line of HTML that looks like this...

  <input type="file" id="image-file" name="files[]" multiple="multiple" style="display: none;" />

What would the javascript look like to create HTML output that looks like this...

 <input type="file" name="files[]" id="image-file" multiple />
 <label class="file-button" for="image-file" >
    <img src="img/upload.png" alt="add"> Upload Your File(s)
 </label>

I'm not sure how to nest HTML tags within other HTML tags with pure javascript, so any help would be greatly appreciated.

3 Answers 3

2

You should begin by creating a DocumentFragment and then you can append each of the child elements to that before inserting the fragment into the DOM.

var docFragment = document.createDocumentFragment();
var input = document.createElement("input");
var label = document.createElement("label");
var img = document.createElement("img");
docFragment.appendChild(input);
docFragment.appendChild(label);
label.appendChild(img);

var form = document.getElementsByTagName("form")[0];
form.appendChild(docFragment);

DocumentFragments are DOM Nodes. They are never part of the main DOM tree. The usual use case is to create the document fragment, append elements to the document fragment and then append the document fragment to the DOM tree. In the DOM tree, the document fragment is replaced by all its children.

Since the document fragment is in memory and not part of the main DOM tree, appending children to it does not cause page reflow (computation of element's position and geometry). Consequently, using document fragments often results in better performance.

Sign up to request clarification or add additional context in comments.

Comments

1

The construction of the individual elements as dom nodes without any content does not change. Assemble the individual parts by employing the appendChild and createTextNode methods as follows:

var input, img, label, text;

input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('id', 'image-file');
input.setAttribute('name', 'files[]');
input.setAttribute('multiple', 'multiple');

label = document.createElement('img');
label.setAttribute('class', 'file-button');
label.setAttribute('for', 'image-file');

img = document.createElement('img');
img.setAttribute('src', 'img/upload.png');
img.setAttribute('alt', 'add');

text = document.createTextNode(' Upload Your File(s)');

label.appendChild(img);
label.appendChild(text);
domNode.appendChild(input);
domNode.appendChild(label);

Notes

  • You probably want to use a documentFragment container for new DOM portions, see Dave Anderson's answer.

  • If you can use jquery, there is a simple alternative:

-

var htmlfrag = $(
    '<input type="file" name="files[]" id="image-file" multiple />\n'
  + '<label class="file-button" for="image-file" >\n'
  + '    <img src="img/upload.png" alt="add"> Upload Your File(s)\n'
  + '</label>\n'
);

  • Instead of the $ function, $.parseHtml() might be preferable as it preserves whitespace as used in the string literal.

  • Attributes on the elements can also be set using json objects; this might be preferable as the attribute set and their values can be compiled programmatically in an easier way.

(Kudos for 2 the latter aspects to Dave Anderson)

5 Comments

He's removed the jQuery tag.
This is a good thought, but I actually need to use pure javascript to get this done
If you just have a big string $.parseHtml() works better otherwise settings attributes is best done with a JSON object $('<input/>', { "type":"file", "id":"image-file" }).
@DaveAnderson Thanks for the hints, adding them to the jquery part of the answer.
A variation of this example was exactly what I was looking for, this was enough to push me in the correct direction. Thank you!
0

Same as you did above, except you have to append the img element to the label element before appending the label to the domNode

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.