1

I'm new to JavaScript and I want to do this: I have an array with objects (an object has a title, cover, author and rating) and I want to populate divs with these objects, one div per object. But I don't know how can I do this without creating new elements (h1, p, img) for every div. This is my first attempt:

// Display the books
var container = document.getElementById('books-container');
function displayBooks(arr) {
	arr.forEach(function(item) {
		var bookRow = document.createElement('div');
		bookRow.className = "row";
		container.appendChild(bookRow);
		var imgColumn = document.createElement('div');
		imgColumn.className = "large-4 columns";
		bookRow.appendChild(imgColumn);
		var imgBook = document.createElement('img');
		imgBook.className = "book-img";
		imgColumn.appendChild(imgBook);
		var bookColumn = document.createElement('div');
		bookColumn.className = "large-8 columns";
		bookRow.appendChild(bookColumn);
		var title = document.createElement('h3');
		title.innerText = item.title;
		bookColumn.appendChild(title);
		var author = document.createElement('p');
		author.innerText = item.author;
		bookColumn.appendChild(author);
		var rating = document.createElement('p');
		rating.innerText = item.rating;
		bookColumn.appendChild(rating);
		var input = document.createElement('input');
		input.type = "checkbox";
		input.className = "checked";
		bookColumn.appendChild(input);
		var wishBtn = document.createElement('button');
		wishBtn.innerText = "Add to wishlist";
		bookColumn.appendChild(wishBtn);
		var hr = document.createElement('hr');
		bookRow.appendChild(hr);
	});	
};
displayBooks(books);

But I think there is a simpler method to this.

I cannot use any libraries. This is a homework assignment, I can only use the functions and objects provided by JavaScript itself.

1
  • Before using pre-built abstractions, you should learn to abstract your own code away into reusable functions. All that repetition can be drastically reduced with a simple createElement function. Commented Jul 12, 2015 at 13:10

2 Answers 2

3

This is where templating engines like Handlebars and similar are really handy: You can define a template which has exactly what you want, and then have the engine render the template using the objects as the basis.

For instance, with handlebars you might do something like this (shamelessly copied from their website):

<script id="entry-template" type="text/x-handlebars-template">
  <div class="entry">
    <h1>{{title}}</h1>
    <div class="body">
      {{body}}
    </div>
  </div>
</script>

And then in your code:

var source   = $("#entry-template").html();
var template = Handlebars.compile(source);
arr.forEach(function(item) {
    container.insertAdjacentHTML("beforeend", template(item));
});

The next version of JavaScript, "ES6", will have template strings as part of the language.


You've said (indirectly) in a comment that you can't use Handlebars. This function will happily take a string with placeholders in the form ${name} and replace all occurrences of those placeholders with the relevant object property. It will fail to replace any tokens that aren't represented by object properties:

function cheapTemplateEval(str, obj) {
    Object.keys(obj).forEach(function(name) {
        str = str.replace(RegExp("\\$\\{" + name + "\\}", "g"), obj[name]);
    });
    return str;
}

Note that this makes the assumption that the property names on the object consist only of characters that are not special in regular expressions.

Live example:

function cheapTemplateEval(str, obj) {
  Object.keys(obj).forEach(function(name) {
    str = str.replace(RegExp("\\$\\{" + name + "\\}", "g"), obj[name]);
  });
  return str;
}
var str = "<p>Hi ${name}, I'm a really ${adjectives} template!</p>";
document.body.insertAdjacentHTML(
  "beforeend",
  cheapTemplateEval(str, {
    name: "Joe",
    adjectives: "nifty and simple"
  })
);

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

Comments

0

I would do this by just appending raw HTML. It can be a bit ugly but it's cleaner than doing it element-by-element in this case.

var container = document.getElementById('container')

var books = [
    {title: 'Catch-22',
     author: 'Joseph Heller'
    },
    {title: 'The Road',
     author: 'Cormac McCarthy'
    }
];

function bookItem(item) {
    return "<h1>" + item.title + "</h1><p>" + item.author + "</p><br />"
}

books.forEach(function(book) {
    var new_div = document.createElement('div')
    new_div.innerHTML = bookItem(book)
    container.appendChild(new_div)
})

JSFiddle

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.