4

I have problem with adding HTML elements in my template string. I want to add new lines in my <li> element, but <br> is interpreted like string.

let movieDescription = document.createTextNode(`${moviesData[i].title} <br> ${moviesData[i].year} <br> ${moviesData[i].genre} <br>${moviesData[i].summary}`);

How can I add <br> element in template string?

Sumurai8
  • 20,333
  • 11
  • 66
  • 100
Ardneh
  • 161
  • 1
  • 3
  • 10
  • 4
    You create a TextNode, so this is the correct behavior. Use `innerHTML` if you want your string to be parsed. – Sirko Dec 23 '17 at 18:39
  • why would you expect any different when creating a *"text node"*? – charlietfl Dec 23 '17 at 18:41
  • You should check out [`diffhtml`](https://diffhtml.org/#html). It has some pretty slick functions that do this and tons of other stuff with template tags. – Patrick Roberts Dec 23 '17 at 19:29

3 Answers3

5

As you have already been informed, <br> is HTML not text. So you'll need to parse the Template Literal in order to render line breaks correctly. The most common way to do it is by using the property .innerHTML, although I've read plenty of posts and blogs about how crappy it is, I've never had a problem with it. In this example, we are using insertAdjacentHTML() (note the template literal has <div>s and <hr>s):

var movieDescription = `
<hr>
<div>Title: ${moviesData[i].title}</div> 
<div>Year: ${moviesData[i].year}</div> 
<div>Genre: ${moviesData[i].genre}</div> 
<div>Summary: ${moviesData[i].summary}</div>
<hr>`;

 document.querySelector('.dock').innerHTML = movieDescription;

An alternative method is insertAdjacentHTML(). It's like innerHTML on steroids.

Pros:

  • it's faster and safer than innerHTML

  • it allows us to specifically determine where the insertion should be relating to the target element:

    • beforebegin: inserted HTML <div>target element</div>

    • afterbegin: <div> inserted HTML target element</div>

    • beforeend: <div>target element inserted HTML </div>

    • afterend: <div>target element</div> inserted HTML

  • It doesn't overwrite content like innerHTML does.

Cons:

  • It's verbose.

Demo

var dock = document.querySelector('.dock');
var i;
var moviesData = [{
  title: 'Pulp Fiction',
  year: '1994',
  genre: 'Drama-Crime',
  summary: "You will know , my name is the Lord, when I lay my vengance upon thee!"
}, {
  title: 'Reservoir Dogs',
  year: '1992',
  genre: 'Drama-Crime',
  summary: "Clowns to the left of me, jokers to the right! Here I am stuck in the middle with you"
}];

for (i = 0; i < moviesData.length; i++) {

  var movieDescription = `
<hr>
<div>Title: ${moviesData[i].title}</div> 
<div>Year: ${moviesData[i].year}</div> 
<div>Genre: ${moviesData[i].genre}</div> 
<div>Summary: ${moviesData[i].summary}</div>
<hr>`;

  dock.insertAdjacentHTML('beforeend', movieDescription);
}
<div class='dock'></div>
Community
  • 1
  • 1
zer00ne
  • 41,936
  • 6
  • 41
  • 68
0

A text node contains... well... text. It does not contain other html elements, and thus when you create one it will interpret the <br> as text and display it as is.

What you want would be a collection of TextNodes and HTMLBRElement.

const movieDescription = [
    document.createTextNode(moviesData[i].title),
    document.createElement('br'),
    document.createTextNode(moviesData[i].year),
    document.createElement('br'),
    document.createTextNode(moviesData[i].genre),
    document.createElement('br'),
    document.createTextNode(moviesData[i].summary)
];

That is quite awkward to do. Instead, you probably want to use Element.innerHTML on the element you want to add this description to.

const html = `${moviesData[i].title} <br> ${moviesData[i].year} <br> ${moviesData[i].genre} <br>${moviesData[i].summary}`;
document.querySelector('.my-movie-description').innerHTML = html;

A similar method exists to add a single TextNode to an element. This is Element.innerText.

Sumurai8
  • 20,333
  • 11
  • 66
  • 100
0

I have witten a html templating engine to render dynamic data at browser.

Codepen example

var moviesData = [];
for(var i = 0; i < 10; i++){
   moviesData.push( {
      "title" : "title " + i,
      "year" : 2000 + i,
      "genre" : "action",
      "summary" : "summary " + i
   });
}
body {
  background-color: #a3d5d3;
}
.movie {
  margin: 0.5em 1em ;
  padding : 0.2em 0.5em;
  border: 1px solid;
}
<div jstl-autorun jstl-foreach="${moviesData}" jstl-foreach-var="movieData">
   <div class="movie">
      ${movieData.title}
      <br/>
      ${movieData.year}
      <br/>
      ${movieData.genre}
      <br/>
      ${movieData.summary}
   </div>      
</div>

here is the link for the template engine

I hope it's useful for you.

TwilightTitus
  • 190
  • 1
  • 9