Home > database >  I'm using a form to push objects to an array but they aren't displaying properly
I'm using a form to push objects to an array but they aren't displaying properly

Time:10-30

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>

  • Related