Search code examples
javascripthtmlarrayssplice

JavaScript - Having trouble splicing an item from an array and then re-rendering that array to my page


Essentially, I'm rendering a couple of notes from a notes[] array to my page and adding a button to each note that, when clicked, will remove the note from the array using splice(), then re-render the remaining notes. The button is given an id based on the title of the note (given as input by a user), which is also given a similar id.

This is just some Vanilla JS for a personal project and after looking around this morning I've yet to find a solution that doesn't deal with Vue, Angular, or some other framework/package.

HTML

This is the relevant HTML:

<main>
  <div id="container">

      <form id="utilities">
          <input type="text" name="userTitle" id="user-title" placeholder="Title" autocomplete="off">
          <input type="text" name="userBody" id="user-body" placeholder="Body" autocomplete="off">
          <div id="buttons">
              <input type="submit" name="userSubmit" id="user-submit" value="Submit">
          </div>
          <input type="text" name="userFilter" id="user-filter" placeholder="Search" autocomplete="off">
      </form>

      <div id="results"></div>

  </div>
</main>

JavaScript

The following JS snippets are all in order, simply broken up for readability and comments.

This is the array I'm passing to and pulling from. It takes a title, a body, an id.

const notes = [{
        title: 'Grocery List',
        body: 'Buy milk, eggs, and bread',
        id: 'grocery-list'
    },
    {
        title: 'Workout Routine',
        body: 'running, push-ups, rowing',
        id: 'workout-routine'
    }
]

This is my function that's getting the title and body text from the user input. It is called in renderNotes().


const results = document.querySelector('#results');

const createElement = function(noteTitle, noteBody) {
    const newNote = document.createElement('div');
    const newTitle = document.createElement('h3');
    const newBody = document.createElement('p');
    const newButton = document.createElement('div');

    newTitle.textContent = noteTitle;
    newTitle.classname = 'note-title';

    newBody.textContent = noteBody;
    newBody.className = 'note-body';

    newButton.className = 'note-button';
    newButton.innerHTML = '&#11199;';
    newButton.id = `button-${newTitle.textContent.toLowerCase()}`.replace(' ', '-');

    newNote.appendChild(newTitle);
    newNote.appendChild(newButton);
    newNote.appendChild(newBody);
    newNote.className = "note";
    newNote.id = newTitle.textContent.toLowerCase().replace(' ', '-');

    results.appendChild(newNote);
}

renderNotes() is simply calling createElement() on each note in that array. Then I'm calling it for the first time.

const renderNotes = function(list) {
    console.log(list)
    list.forEach(function(item) {
        createElement(item.title, item.body)
    })
}

renderNotes(notes);

This snippet seems to be where I'm failing. It should be getting each button (created during the createElement() calls) and adding an eventListener('click') to it. Then it is supposed to look through each of the notes in notes[], find the one which has a similar id to that of the button pressed, and splice() that note from the notes[] array. Then I simply want to re-render the notes.

document.querySelectorAll('.note-button').forEach(function(button) {
    button.addEventListener('click', function(e) {
        notes.forEach(function(note) {
            if (e.target.id.includes(note.id)) {
                notes.splice(notes.indexOf(note), 1)
            }
            renderNotes(notes)
        })
    })
});

Actual Results

The notes seem to be spliced from the array consistently, but my problem lies in getting them to re-render. Currently it's just removing the items and then either failing to render or is adding more copies to the page. Edit to add: I'm not receiving any errors in the console, the code is just executing properly as far as the computer is concerned. So I know it's definitely a "Problem Between Chair and Keyboard" error.

Hopefully this makes sense. I appreciate any responses.


Solution

  • You're calling renderNotes(notes) at each iteration not only after the array was mutated.

    Try something like:

    const clickedNote = notes.find(note => e.target.id.includes(note.id));
    notes.splice(notes.indexOf(clickedNote), 1);
    renderNotes(notes);
    

    A better solution will be to define notes using let and then do something like this:

    notes = notes.filter(note => !e.target.id.includes(note.id));
    renderNotes(notes);