0

I am struggling to get this working and would like to know if i'm headed in the right direction with what i have.

Whats supposed to be happening is two input fields that get added to a on a click event. This part is done and its working fine.

Whats supposed to happen after the input fields get added to the table is you can then delete a tr with a button that gets added when the tr is created. Which is not working. I also cant figure out why the page refreshes when you click the delete button to delete a tr, preventDefault() is being used.

let data             = [];
let speciesInput     = document.querySelector('#speciesInput')
let breedInput       = document.querySelector('#breedInput')
let messageBox       = document.getElementById("display");
const addProductBtn  = document.querySelector('#addValue')
let deleteProductBtn = document.getElementsByClassName('deleteProduct')
const deleteBtnArray = Array.from(deleteProductBtn)

addProductBtn.addEventListener('click', function (e) {
    e.preventDefault();

    let species, breed;
    species = speciesInput.value;
    breed   = breedInput.value;

    data.push({
        species: species,
        breed: breed,
    });
    clearAndShow();
})  

function clearAndShow() {
    // Clear our fields
    speciesInput.value   = "";
    breedInput.value     = "";
    messageBox.innerHTML = computeHTML();
}

function computeHTML() {
    let html = "<table>";
    data.forEach(function (item) {
        html += "<tr>";
        html += "<td>" + item.species + '&nbsp' + "</td>" 
        html += "<td>" + item.breed + "</td>"
        html += "<td>" + "<button class='deleteProduct' onclick='deleteProduct()'> &#8722; </button>" + "</td>"
        html += "</tr>"
        console.log(deleteBtnArray)
    });
    html += "</table>"
    return html;
}

function deleteProduct() {
    console.log(deleteBtnArray)
    deleteBtnArray.forEach((btn) => {
        btn.addEventListener('click', function (e) {
            e.preventDefault();
            console.log('Delete item')
            deleteItem() // Not made yet
        })
    })
}
deleteProduct()



document.querySelector('#productForm').addEventListener('submit', function (e) {
    e.preventDefault();
})
<!-- Add Product -->
<div class="">
  <div class="d-flex flex-column justify-content-center align-content-center">
    <div class="intro-wrapper">
      <h1 class="welcome-heading">Welcome <span class="brand-heading"></span><span class="brand-heading brand-heading-grey"></span></h1>
      <span class="intro-description">Set up your profile to begin interacting with the community.</span>
    </div>
    <span class="secondary-txt mt-5 mb-2">Add Your Product For Display</span>
    <form id="productForm" class="form d-flex flex-column align-items-center mt-2" action="">
      <div class="product-field-outter">
        <div class="form-field product-field-inner d-flex flex-column align-items-center">
          <div style="width: 100%!important;" class="form-field my-auto">
            <label for="species"></label>
            <input id="speciesInput" class="sign-up-inputs addProductInputs" type="text" placeholder="Species">
          </div>
          <div style="width: 100%!important;" class="form-field my-auto">
            <label for="breed"></label>
            <input id="breedInput" class="sign-up-inputs addProductInputs" type="text" placeholder="Breed">
          </div>
          <small></small>
          <button id="addValue" class="add-product-btn btn-active mt-4 ms-2">&#43;</button>
        </div>
      </div>
      <div id="display" class="output d-flex flex-column justify-content-center mt-5"></div>
      <!-- <ul id="list" class="productList justify-content-between"></ul> -->
      <button class="primary-btn continue-btn btn-active mt-4">Continue</button>
    </form>
    <button class="back-btn btn-active me-auto mt-4">Back</button>
  </div>
</div>
</div>
<!-- Add Product -->
<div class="">
    <div class="d-flex flex-column justify-content-center align-content-center">
        <div class="intro-wrapper">
            <h1 class="welcome-heading">Welcome<span class="brand-heading"></span><span class="brand-heading brand-heading-grey"></span></h1>
            <span class="intro-description">Set up your profile to begin interacting with the community.</span>
        </div>
        <span class="secondary-txt mt-5 mb-2">Add Your Product For Display</span>
        <form class="form d-flex flex-column align-items-center mt-2" action="">
            <div class="product-field-outter">
                <div class="form-field product-field-inner d-flex flex-column align-items-center">
                    <div style="width: 100%!important;" class="form-field my-auto">
                        <label for="species"></label>
                        <input id="speciesInput" class="sign-up-inputs addProductInputs" type="text" placeholder="Species">
                    </div>
                    <div style="width: 100%!important;" class="form-field my-auto">
                        <label for="breed"></label>
                        <input id="breedInput" class="sign-up-inputs addProductInputs" type="text" placeholder="Breed">
                    </div>
                    <small></small>
                    <button id="addValue" class="add-product-btn btn-active mt-4 ms-2">&#43;</button>
                </div>
            </div>
            <div id="display" class="output d-flex flex-column justify-content-center mt-5"></div>
            <!-- <ul id="list" class="productList justify-content-between"></ul> -->
            <button class="primary-btn continue-btn btn-active mt-4">Continue</button>
        </form>
        <button class="back-btn btn-active me-auto mt-4">Back</button>
        </div>
    </div>
</div>

Javascript

let data = [];
let speciesInput = document.querySelector('#speciesInput')
let breedInput = document.querySelector('#breedInput')

let messageBox = document.getElementById("display");
const addProductBtn = document.querySelector('#addValue')
let deleteProductBtn = document.getElementsByClassName('deleteProduct')
const deleteBtnArray = Array.from(deleteProductBtn)

addProductBtn.addEventListener('click', function (e) {
    e.preventDefault();

    let species, breed;
    species = speciesInput.value;
    breed = breedInput.value;

    data.push({
        species: species,
        breed: breed,
    });
    clearAndShow();
})  

function clearAndShow() {
    // Clear our fields
    speciesInput.value = "";
    breedInput.value = "";
    messageBox.innerHTML = computeHTML();
}

function computeHTML() {
    let html = "<table>";
    data.forEach(function (item) {
        html += "<tr>";
        html += "<td>" + item.species + '&nbsp' + "</td>" 
        html += "<td>" + item.breed + "</td>"
        html += "<td>" + "<button class='deleteProduct' onclick='deleteProduct()'> &#8722; </button>" + "</td>"
        html += "</tr>"
        console.log(deleteBtnArray)
    });
    html += "</table>"
    return html;
}

function deleteProduct() {
    console.log(deleteBtnArray)
    deleteBtnArray.forEach((btn) => {
        btn.addEventListener('click', function (e) {
            e.preventDefault();
            console.log('Delete item')
            deleteItem() // Not made yet
        })
    })
}
deleteProduct()
Halp_am_stuck
  • 199
  • 2
  • 15
  • 1
    _“I also cant figure out why the page refreshes when you click the delete button”_ — A [` – Sebastian Simon Sep 12 '21 at 01:43
  • 1
    Inline event handlers like `onclick` are [not recommended](/q/11737873/4642212). They are an [obsolete, hard-to-maintain and unintuitive](/a/43459991/4642212) way of registering events. Always [use `addEventListener`](//developer.mozilla.org/docs/Learn/JavaScript/Building_blocks/Events#inline_event_handlers_%E2%80%94_dont_use_these) instead. – Sebastian Simon Sep 12 '21 at 01:43
  • 1
    Use [event delegation](//developer.mozilla.org/docs/Learn/JavaScript/Building_blocks/Events#Event_delegation) instead of assigning multiple event listeners — it’s more maintainable, and applies to dynamically added elements. E.g., use an [event argument](//developer.mozilla.org/docs/Web/API/EventTarget/addEventListener#The_event_listener_callback)’s [`target`](//developer.mozilla.org/docs/Web/API/Event/target). See [the tag info](/tags/event-delegation/info) and [What is DOM Event delegation?](/q/1687296/4642212). – Sebastian Simon Sep 12 '21 at 01:43
  • Thank you for these suggestions! i will probably refactor this a bit after i get it working... I'm also still really new to javascript – Halp_am_stuck Sep 12 '21 at 01:55

1 Answers1

1

There is more than one thing happening

  1. The variables on top of your JS code are recovering elements from the document object only when the page loads. You are not updating them (I.E. the deleteBtnArray) after appending the html on clearAndShow() function. That's why the deleteBtnArray is always empty when you click the - buttons. One way to avoid this is collectiong the elements inside the deleteProduct function. Also, you don't need to convert into array using Array.from because document.getElementsByClassName(...) already returns an iterable collection. Also, using "for of" is a little better readable than forEach with callbacks.

  2. You are adding the deleteProduct(...) function more than once using this method, because you are calling using the onclick='deleteProduct()' and also btn.addEventListener('click'...). And after that you also call the deleteProduct function right after its declaration. No need for that.

  3. If you want to remove the whole <tr>, there is a easy way of doing that referencing each <tr> with an id and using it as argument for the deleteProduct function, just like in the example below

Replace your whole javascript by this, and use the same HTML

let data = [];
var speciesInput = document.querySelector('#speciesInput')
var breedInput = document.querySelector('#breedInput')
var messageBox = document.getElementById("display");
var addProductBtn = document.querySelector('#addValue')

addProductBtn.addEventListener('click', function (e) {
  e.preventDefault();

  let species, breed;
  species = speciesInput.value;
  breed = breedInput.value;

  data.push({
    species: species,
    breed: breed,
  });
  clearAndShow();
})

function clearAndShow() {
  // Clear our fields
  speciesInput.value = "";
  breedInput.value = "";
  messageBox.innerHTML = computeHTML();
}

function computeHTML() {
  let html = "<table>";
  data.forEach(function (item, index) {
    html += "<tr id='line-" + index + "'>";
    html += "<td>" + item.species + '&nbsp' + "</td>"
    html += "<td>" + item.breed + "</td>"
    html += "<td>" + "<button onclick='deleteProduct(" + index + ")'> &#8722; </button>" + "</td>"
    html += "</tr>"
  });
  html += "</table>"
  return html;
}

function deleteProduct(removedIndex) {
  document.getElementById("line-" + removedIndex).remove()
  data = data.filter(function (item, index) { return index != removedIndex })
}

document.querySelector('#productForm').addEventListener('submit', function (e) {
  e.preventDefault();
})

Bonus:

I recommend you to use ` instead of " or ' when writing html inside strings, because

  • You can insert variables using ${variableName}
  • You can break lines
  • You can use ' and " freely inside strings delimited by `
  • You don't need to use a lot of +=

I also recommend you to use .map( instead of .forEach(. Things get cleaner this way.

Replace the computeHTML() I've shown before with this piece of code:

function itemHtml(item, index) {
  return `<tr id="line-${index}">
    <td>${item.species}</td>
    <td>${item.breed}</td>
    <td><button onclick="deleteProduct(${index})"> &#8722; </button></td>
  </tr>`
}

function computeHTML() {
  return `<table>${data.map(itemHtml)}</table>`
}
  • Thank you for doing this, ive been stuck on this for a while. I really appreciate you taking the time to explain things as-well it really helps me out. If u do have time there are a couple lines i done really understand how its working... – Halp_am_stuck Sep 12 '21 at 05:17
  • When you use ` instead of " or ' on beginning and ending of strings, you can put variables inside the string and their values will be inserted there. You just need to wrap the variable inside ${ and } Example: var name = "Caio" var phrase = `My name is ${name}, you khow?` Also, the index will be a counter with the "position" of every element inside the original array (in this case, the array is the variable "data"). So, the first will have an id="line-0", the second one will have "line-1" – Caio Felipe Giasson Sep 14 '21 at 05:08