I'm creating a library app where users input data into a form
and the values they enter are displayed in its own div
.
I have this array
let myLibrary = [
{
title: "The Once and Future King",
author: "White",
pages: 654,
},
{
title: "The Hobbit",
author: "Tolkien",
pages: 304,
},
];
which is automatically displaying each object
(for testing purposes) on my page thanks to this forEach()
myLibrary.forEach((book) => {
const bookContent = document.getElementById("content");
const addBook = document.createElement("div");
addBook.className = "book";
bookContent.appendChild(addBook);
addBook.innerHTML = `
<div >
<p >
<span>${book.title}</span>
</p>
</div>
<div >
<p>
Author: <span>${book.author}</span>
</p>
<p>
Pages: <span>${book.pages}</span>
</p>
</div>`;
});
The forEach
makes it so every object
inside my array
is displayed in its own 280x365 pixel div
and the book title, author and page count is displayed in it's own p
element. I'm also using flex
for organization.
I also have a form
which users can input a new book title, author and page number to add to their growing book collection.
const form = document.getElementById("form");
form.addEventListener("submit", updateLibrary);
function updateLibrary(event) {
event.preventDefault();
const title = document.getElementById("title").value;
const author = document.getElementById("author").value;
const pages = document.getElementById("pages").value;
const book = {
title: title,
author: author,
pages: parseInt(pages),
};
myLibrary.push(book);
console.log(myLibrary);
}
When I fill the form out, everything appears to work perfectly. I have console.log
in my updateLibrary
function and I notice the object
is being pushed into the array
like I want it to. But every time I hit the submit
button, a new div
isn't being created for the new book. I'm guessing this has to do with my forEach
not triggering the new object
but I can't find a way to fix this.
How can I better write my code so a new div
is also being created with the new object
every time I submit the form
?
What I've tried
I've tried rearranging my code so the forEach
is below the array
, so the updateLibrary
function is above and below the forEach
.
I've also tried putting the forEach
inside the updateLibrary
function. That did make it work but it gave me an even worse bug.
CodePudding user response:
That is normal. The DOM (so the HTML within the page) is not automatically updated everytime that you change your array. If you want to work like this, I suggest you to look at ReactJS.
But to solve your problem, you must do 3 easy things here : create a function that will handle the display of your object in HTML, update your forEach to only call this new function, then, when a user create a new object, apply it this function :
const bookContent = document.getElementById("content");
function displayBook(book) {
const addBook = document.createElement("div");
addBook.className = "book";
bookContent.appendChild(addBook);
addBook.innerHTML = `
<div >
<p >
<span>${book.title}</span>
</p>
</div>
<div >
<p>
Author: <span>${book.author}</span>
</p>
<p>
Pages: <span>${book.pages}</span>
</p>
</div>`;
}
// Display your original object list
myLibrary.forEach((book) => {
displayBook(book)
});
// Handle your object creation
const form = document.getElementById("form");
form.addEventListener("submit", updateLibrary);
function updateLibrary(event) {
event.preventDefault();
const title = document.getElementById("title").value;
const author = document.getElementById("author").value;
const pages = document.getElementById("pages").value;
const book = {
title: title,
author: author,
pages: parseInt(pages),
};
myLibrary.push(book);
// Then, ask to display your book
displayBook(book)
console.log(myLibrary);
}
It should work fine :)
CodePudding user response:
You can also use Proxy objects to update the DOM the moment you add a new book to the myLibrary
array. For this, we will convert the myLibrary
array into a new proxy object named libraryProxy
and configure it.
const myLibrary = [{
title: "The Once and Future King",
author: "White",
pages: 654,
},
{
title: "The Hobbit",
author: "Tolkien",
pages: 304,
},
];
const libraryProxy = new Proxy(myLibrary, {
get(target, prop) {
return target[prop];
},
// When you add a new element to the array,
// the set method will run and here we will update the DOM
// while adding the new element as newVal to the array.
set(target, prop, newVal) {
if (Number(prop)) {
const book = newVal;
// add new book to array
target[prop] = book;
// update the dom
addBookToUI(book);
};
return true;
}
})
const bookContent = document.getElementById("content");
const form = document.getElementById("form");
form.addEventListener("submit", submitHandler);
libraryProxy.forEach((book) => {
addBookToUI(book);
})
function submitHandler(event) {
event.preventDefault();
const [title, author, pages] = document.querySelectorAll('form > input');
// New book will be added to the array and the DOM will be updated
libraryProxy.push({
title: title.value,
author: author.value,
pages: parseInt(pages.value, 10)
});
}
function addBookToUI(book) {
const bookEl = document.createElement('div');
bookEl.className = 'book';
bookContent.appendChild(bookEl);
bookEl.innerHTML = `
<div >
<p >
<span>${book.title}</span>
</p>
</div>
<div >
<p>
Author: <span>${book.author}</span>
</p>
<p>
Pages: <span>${book.pages}</span>
</p>
</div>
`;
}
.book {
border: 1px solid #000;
margin: 5px 0;
font-size: 14px;
}
<form id="form">
<input type="text" id="title" placeholder="title" />
<input type="text" id="author" placeholder="author" />
<input type="text" id="pages" placeholder="pages" />
<button type="submit">save</button>
</form>
<div id="content"></div>