Home > Net >  Update an Object Array with user input & then display the updated array in JavaScript
Update an Object Array with user input & then display the updated array in JavaScript

Time:06-19

I have an array with an item already inside that displays when you first open the page. I've created a form that takes user input data (name comment) and pushes it to the array on button click. I want the updated array to display its new content without duplicating what is already displayed.

Eg: On page load, display existing item. On button submit, display new item existing item. There should be 2 items displaying now. On button submit again, display new item 2 existing items. There should be 3 items displaying now.

I have tried calling the function (generateCommentRows()) that displays the array content, but, this just displays content again. I've thought about creating a function that clears the comment area and then calls (generateCommentRows()) again, but, I would prefer to learn how to update it.

I know it must be a simple issue but I can't seem to think of it right now.

The array:

    const commentsArray = [
  {
    name: "Barack Obama",
    pfp: "./assets/images/image.jpg",
    date: "02/17/2021",
    comment:
      "blah blah",
  }
];

Displaying the array content:

const generateCommentsRows = () => {
  commentsArray.forEach((event) => {
    const commentContainer = document.createElement("article");
    commentContainer.classList.add("comments__area__lower__row");

    const nameEl = document.createElement("p");
    nameEl.classList.add("comments__area__lower__row__name");
    nameEl.innerText = event.name;

    const pfpEl = document.createElement("img");
    pfpEl.classList.add("comments__area__lower__row__pfp");
    pfpEl.src = event.pfp;

    const dateEl = document.createElement("p");
    dateEl.classList.add("comments__area__lower__row__date");
    dateEl.innerText = event.date;

    const commentsEl = document.createElement("p");
    commentsEl.classList.add("comments__area__lower__row__comments");
    commentsEl.innerText = event.comment;

    commentContainer.appendChild(pfpEl);
    commentContainer.appendChild(nameEl);
    commentContainer.appendChild(dateEl);
    commentContainer.appendChild(commentsEl);
    const lowerCommentsArea = document.querySelector(".comments__area__lower");

    lowerCommentsArea.appendChild(commentContainer);
  });
};
generateCommentsRows();

Input form to array:

const pushData = (event) => {
  let comments = {
    name: document.getElementById("name").value,
    pfp: "./assets/images/image.jpg",
    date: Date.now(),
    comment: document.getElementById("commentText").value,
  };
  commentsArray.unshift(comments);
};

let myBtn = document.getElementById("submitBtn");
myBtn.onclick = function () {
  pushData();
};

This code is displayed in the order it's written in my .js file.

UPDATE: I managed to get the intended outcome by clearing the comment area and then simply recalling the function that displays the array. Again, however, if there's a way to dynamically update the array without recalling the function, that would be great to learn.

CodePudding user response:

You can extract the code to add a single comment to the page to a separate function, with a parameter indicating whether to insert to the front or back of the comment list. (For adding to the front, Element#prepend can be used and Element#append can be used otherwise.) When displaying the initial array of comments, loop over the original array and can this function with the parameter set to false. On receiving a new comment, call this function with the newly added first element of the array and set the parameter to true.

const commentsArray = [
  {
    name: "Barack Obama",
    pfp: "./assets/images/image.jpg",
    date: "02/17/2021",
    comment:
      "blah blah",
  }
];
const addComment = (comment, addFront=false) => {
    const commentContainer = document.createElement("article");
    commentContainer.classList.add("comments__area__lower__row");

    const nameEl = document.createElement("p");
    nameEl.classList.add("comments__area__lower__row__name");
    nameEl.innerText = comment.name;

    const pfpEl = document.createElement("img");
    pfpEl.classList.add("comments__area__lower__row__pfp");
    pfpEl.src = comment.pfp;

    const dateEl = document.createElement("p");
    dateEl.classList.add("comments__area__lower__row__date");
    dateEl.innerText = comment.date;

    const commentsEl = document.createElement("p");
    commentsEl.classList.add("comments__area__lower__row__comments");
    commentsEl.innerText = comment.comment;

    commentContainer.appendChild(pfpEl);
    commentContainer.appendChild(nameEl);
    commentContainer.appendChild(dateEl);
    commentContainer.appendChild(commentsEl);
    const lowerCommentsArea = document.querySelector(".comments__area__lower");

    lowerCommentsArea[addFront ? 'prepend': 'append'](commentContainer);
}
const generateCommentsRows = () => {
  commentsArray.forEach(addComment);
};
generateCommentsRows();
const pushData = (event) => {
  let comments = {
    name: document.getElementById("name").value,
    pfp: "./assets/images/image.jpg",
    date: Date.now(),
    comment: document.getElementById("commentText").value,
  };
  commentsArray.unshift(comments);
};

let myBtn = document.getElementById("submitBtn");
myBtn.onclick = function () {
  pushData();
  addComment(commentsArray[0], true);
};
Name: <input id="name">
Comment: <input id="commentText">
<button id="submitBtn">
Submit
</button>
<br>
Comments:
<div >
</div>

CodePudding user response:

Sounds like you need to identity whether the string in the name field exists in the array of objects already. Don't unconditionally push to the array - only do so if the object doesn't already exist. If the object does already exist, replace it with the new one.

With the updated data, you can then either clear the whole container and call generateCommentsRows again, or identify the index of the name in the array to target the date and comment elements in the DOM that need to be changed.

const pushData = () => {
    const name = document.getElementById("name").value;
    const date = Date.now();
    const comment = document.getElementById("commentText").value;
    const foundObj = commentsArray.find(obj => obj.name === name);
    if (foundObj) {
        foundObj.date = date;
        foundObj.comment = comment;
    } else {
        commentsArray.push({
            name,
            pfp: "./assets/images/image.jpg",
            date,
            comment,
        });
    };
    generateCommentsRows();
};

document.getElementById("submitBtn").addEventListener('click', pushData);

and empty the container inside generateCommentsRows before populating it again:

const generateCommentsRows = () => {
  lowerCommentsArea.textContent = '';
  commentsArray.forEach((event) => {
    // ...

Or, if you don't want to call generateCommentsRows again:

  • put the callback that generates an <article> in a separate function so you can call it when a new name is added, without duplicating all the code again
  • use .findIndex instead of .find to identify if the object already exists in the array, and if it does, use that index to navigate to the appropriate descendant of the lowerCommentsArea
// this parameter is not an event, consider renaming it to something more appropriate
const insertComment = (event) => {
  const commentContainer = document.createElement("article");
 
 commentContainer.classList.add("comments__area__lower__row");
  // ...

const generateCommentsRows = () => {
  commentsArray.forEach(insertComment);
};

const pushData = () => {
    const name = document.getElementById("name").value;
    const date = Date.now();
    const comment = document.getElementById("commentText").value;
    const foundIndex = commentsArray.findIndex(obj => obj.name === name);
    if (foundIndex !== -1) {
        commentsArray[foundIndex].date = date;
        commentsArray[foundIndex].comment = comment;
        lowerCommentsArea.children[foundIndex].querySelector('.comments__area__lower__row__date').textContent = date;
        lowerCommentsArea.children[foundIndex].querySelector('.comments__area__lower__row__comments').textContent = comment;
    } else {
        const commentObjToPush = {
            name,
            pfp: "./assets/images/image.jpg",
            date,
            comment,
        };
        commentsArray.push(commentObjToPush);
        insertComment(commentObjToPush);
    };
};
  • Related