Reputation: 21
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.
Upvotes: 1
Views: 81
Reputation: 1074979
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"
})
);
Upvotes: 3
Reputation: 1394
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)
})
Upvotes: 0