0

I have the following sample codes. I'm trying to add some class to the id="section" inside the javascript code but unsuccessful. Error: Cannot read property 'classList' of null when removing the commented codes. Any helps would be greatly appreciated!

Part 1:

var template = document.querySelector('#container').innerHTML;
var contents = '';
var section = document.createElement("div");

// These two lines cause the error
var section = document.getElementById("section");
section.classList.add("bg-yellow");

contents = template.replace(/\{\{title\}\}/, "Title");
section.insertAdjacentHTML('beforeend', contents);
document.getElementById('content').appendChild(section);

Part 2: (Updated from Randy Casburn's orig answer)

var data = [{
"Title": "One"},
{"Title": "Two"},
{"Title": "Three"}];

var template = document.querySelector('#container').innerHTML;
var contents = '';
var section = document.createElement("div");

for(var i = 0; i < data.length; i++){
 contents += template.replace(/\{\{title\}\}/, data[i].Title);
}

section.innerHTML = contents;
var innerSection = section.querySelector("#section");
innerSection.classList.add("bg-yellow","blue");

document.getElementById('content').appendChild(section);
.sub-section{
  background: tomato;
  width: 100px;
}
.bg-yellow{
  background: yellow!important;
  width: 100%;
  height: auto;
}
.blue{
  color: blue!important;
}
<div id="content"></div>
<script type="template" id="container">
 <div id="section">
  <div class="sub-section">
   <h1>{{title}}</h1>
  </div>
 </div>
</script>
Le Vic
  • 701
  • 4
  • 13
  • Are you saying the error occurs when you *uncomment* those lines? – MTCoster Jan 18 '19 at 15:31
  • @MTCoster yes, that's right – Le Vic Jan 18 '19 at 15:33
  • 1
    The browser ignores everything inside the `` block. Thus you can not query it before adding it to the DOM properly. You read it, yet never add it to the DOM. – Lain Jan 18 '19 at 15:33
  • You cannot put html inside script tags – Pete Jan 18 '19 at 15:34
  • 1
    You can put whatever you want inside script tags, however the browser interpret it as plain text: https://stackoverflow.com/a/5679857/2831645 – thibpat Jan 18 '19 at 15:34
  • @Pete: You can actually https://stackoverflow.com/questions/4912586/explanation-of-script-type-text-template-script – Lain Jan 18 '19 at 15:35
  • `document.getElementById("section")` returns `null`, most likely because the template is not inserted yet into the DOM tree. – sjahan Jan 18 '19 at 15:37
  • @Lain script type - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script: *Omitted or a JavaScript MIME type*: Mime types: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#JavaScript_types - I don't see any `type/template` mime type in that list of allowed types - perhaps the question you link to is out of date (was asked and answered in 2012)? Also searching w3c, it lists no such thing – Pete Jan 18 '19 at 15:44
  • @Lain try validating that in the w3c validator you get: Error: Bad value template for attribute type on element script: Subtype missing. From line 9, column 1; to line 9, column 39 >↩↩↩ – Pete Jan 18 '19 at 15:46
  • @Pete: That does not make it not working Pete. I never said that it was valid HTML according to the w3c validator. I wrote that I can write whatever I feel like inside a script tag as long as it is not a permitted type. And, if you like it or not, it does work as you can see in various links on this platform. – Lain Jan 18 '19 at 15:48

2 Answers2

2

This is quite simple to accomplish. Create the div and set its innerHTML as the template contents. Then add the div to the DOM.

You were on the right track, but just skipped the one vital step.

var data = [{
"Title": "One"},
{"Title": "Two"},
{"Title": "Three"}];

var template = document.querySelector('#container').innerHTML;
var contents = '';
for(var i = 0; i < data.length; i++){
 contents += template.replace(/\{\{title\}\}/, data[i].Title);
}

//var contents = template.replace(/\{\{title\}\}/, "Title");;
var section = document.createElement("div");
section.innerHTML = contents;
var innerSection = section.querySelectorAll(".section");
innerSection.forEach(el=>el.classList.add("bg-yellow"));
document.getElementById('content').appendChild(section);
.sub-section {
  background: tomato;
  width: 100px;
}

.bg-yellow {
  background: yellow!important;
  width: 100%;
  height: auto;
}
<div id="content"></div>
<script type="template" id="container">
  <div class="section">
    <div class="sub-section">
      <h1>{{title}}</h1>
    </div>
  </div>
</script>

EDIT: OP changed the use case in the question, so this updates the answer to reflect the new question :-/

Randy Casburn
  • 11,404
  • 1
  • 12
  • 26
  • You are now adding it twice. `section.innerHTML = template.replace(/\{\{title\}\}/, "Title");` and just add it once would be the way to go most likely. – JavaScript Jan 18 '19 at 15:39
  • @JavaScript - thanks that was an oversight. I'll correct. – Randy Casburn Jan 18 '19 at 15:43
  • @K.C. - The `classList.add()` method takes a comma separated list of class names to add all at once (if that's what you mean). See line 23 in the example: https://developer.mozilla.org/en-US/docs/Web/API/Element/classList#Examples – Randy Casburn Jan 18 '19 at 16:13
  • @RandyCasburn thanks. I'm wanting to challenge this solution when there is an array of data. The class seems to only apply to the first element. I'll update my codes above with the test data. Would u take a look at it, please? – Le Vic Jan 18 '19 at 16:16
  • @K.C. - You cannot do that with your current template because you set an `id` attribute in your template. While creating multiple elements from that template you will duplicate that `id` value which is not allowed (ids must be unique). – Randy Casburn Jan 18 '19 at 16:21
  • @K.C. - I modified my code to accommodate your new question. Note I changed the `id` to `class`, collected `All` of the nodes now, then iterated `forEach` and applied your class names. That should answer that query. – Randy Casburn Jan 18 '19 at 16:27
  • @K.C. - Rather than modifying an answered question, it is best to create a new question. That way others can benefit from the original question as well as the new. So if this answers your question please see: [What should I do when someone answers my question?](https://stackoverflow.com/help/someone-answers) – Randy Casburn Jan 18 '19 at 16:30
  • @RandyCasburn thank you for the suggestion. I'll modify my question to reflect both previous and new issues to your answers. – Le Vic Jan 18 '19 at 16:35
0

If you specify a content type other than Javascript in Script tags (or another scripting language that the browser understands), it will not be interpreted by the browser, and you can just access it as plain text.

refer( How does HTML tags work inside script tag? )

you do not have the html DOM that you put in you script but you are trying to query on it.