How to pass id to delete function

Asked

Viewed 197 times

4

I’m creating a to-do list, I can create fields with tasks, and elements with javascript, but when I click the close button, the only field that disappears is the last one. I place the created elements in an object-shaped array and assign a value to each created array, but I cannot pass this value to the exclude function so that the button deletes the entire field. What can I do?

var myNodelist = document.getElementsByTagName("LI");
var index = 0;
var array = [];

for (var i = 0; i < myNodelist.length; i++) {
  var span = document.createElement("SPAN");
  var txt = document.createElement("button");
  var xis = document.createTextNode("\u00D7");

  span.appendChild(txt);
  txt.appendChild(xis);
  txt.className = "close";
  myNodelist[i].appendChild(txt);

}


var close = document.getElementsByClassName("close");
for (var i = 0; i < close.length; i++) {
  close[i].onclick = function() {
    var div = this.parentElement;
    div.style.display = "none";
  }
}

function newElement() {

  var li = document.createElement("input");
  var ul = document.createElement("input");
  var done = document.createElement("input");
  done.setAttribute("type", "checkbox");
  var inputText = document.getElementById("myInput").value;
  var inputDate = document.getElementById("time").value;

  done.className = "checkIn";
  li.value = inputText;
  li.className = "valor";
  ul.value = inputDate;
  ul.className = "data";

  var span = document.createElement("SPAN");
  var txt = document.createElement("button");
  var xis = document.createTextNode("\u00D7");

  span.appendChild(txt);
  txt.appendChild(xis);
  txt.className = "close";

  if (inputText === '') {
    alert("Você precisa digitar algo primeiro!");
  } else {
    document.getElementById("recent").appendChild(done).style.width = "20px";
    document.getElementById("recent").appendChild(li);
    document.getElementById("recent").appendChild(ul).style.width = "90px";
    document.getElementById("recent").appendChild(span);

  }

  array.push({
    inputtexto: li,
    inputdata: ul,
    close: txt
  })
  index++;

  for (var i = 0; i < close.length; i++) {
    close[i].onclick = function() {
      var div = this.parentNode;
      div.style.display = "none";
      done.style.display = "none";
      li.style.display = "none";
      ul.style.display = "none";
    }
  }
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>
  <form method="POST" action="">
    <label for="add-task">Título:</label>
    <input type="text" id="myInput" name="titulo">
    <label for="date">Prazo:</label>
    <input type="date" id="time" name="data" /><br><br>
    <span onclick="newElement();" class="addBtn" id="newtask" style="cursor:pointer">Add</span>
  </form>
  <div id="recent" class="recent">

  </div>
</body>

</html>

  • It has several problems in the code, being one of the most direct this close.lenght in which length is misspelled. The idea of creating all knots by hand is to learn? Because this html creation becomes much simpler by creating a string with the new html and changing directly with innerHTML. The for (var i...) { close[i] =function(){.. also has a closures problem

  • lenght fixed. Yes, I’m still learning so I prefer to do everything by hand and with pure javascript.Thanks if you can help me out.

2 answers

0


  • The biggest problem, as @Dvd had already said, is the fact that an html element is missing to encompass each new line that is inserted, because the fields are inserted in a following way, ending up having no parent element to group them. This makes it difficult to hide.
  • The code you initially have before the function newElement is not necessary as it tries to add elements based on the amount of <li> of the document, but there is no.
  • Each time you add a new element to html you don’t need one for to assign all the functions of click of closes, but only the element that was added.
  • Has a problem of closures in:

     for (var i = 0; i < close.length; i++) {
         close[i].onclick = function() {
    

    Because the i will end up having no scope of the for and all the close-ups will mention the latest i. Consider the following verifiable example of the problem:

    const spans = document.querySelectorAll(".s");
    
    for (var i = 0; i < spans.length; ++i){
      spans[i].onclick = function(){
        console.log("click no span numero " + i);
      }
    }
    Clique nos números que se seguem:
    <span class="s">1</span>
    <span class="s">2</span>
    <span class="s">3</span>
    <span class="s">4</span>
    <span class="s">5</span>

Here it clearly sees that the i has no scope of the for and it ends up being the same for all elements. Moreover it is the value in which came out of the for that is 5 and we only have spans of 0 to 4.

At this point one of the simplest ways to solve this problem is by declaring the i with let which ensures the scope of for and makes the closure function as expected:

const spans = document.querySelectorAll(".s");

for (let i = 0; i < spans.length; ++i){
  spans[i].onclick = function(){
    console.log("click no span numero " + i);
  }
}
Clique nos números que se seguem:
<span class="s">1</span>
<span class="s">2</span>
<span class="s">3</span>
<span class="s">4</span>
<span class="s">5</span>

Setting these details your code would look like this:

var index = 0;
var array = [];

//obter o elemento do html apenas uma vez
const recent = document.getElementById("recent"); 

function newElement() {
  var li = document.createElement("input");
  var ul = document.createElement("input");
  var done = document.createElement("input");
  done.setAttribute("type", "checkbox");
  var inputText = document.getElementById("myInput").value;
  var inputDate = document.getElementById("time").value;

  done.className = "checkIn";
  li.value = inputText;
  li.className = "valor";
  ul.value = inputDate;
  ul.className = "data";

  var span = document.createElement("SPAN");
  var txt = document.createElement("button");
  var xis = document.createTextNode("\u00D7");
  var newdiv = document.createElement("div");

  span.appendChild(txt);
  txt.appendChild(xis);
  txt.className = "close";

  if (inputText === '') {
    alert("Você precisa digitar algo primeiro!");
  } else {
    //todos os elementos são adicionados ao novo div que os agrupa
    newdiv.appendChild(done).style.width = "20px";
    newdiv.appendChild(li);
    newdiv.appendChild(ul).style.width = "90px";
    newdiv.appendChild(span);
    recent.appendChild(newdiv); //novo div adicionado ao recent
  }

  array.push({
    inputtexto: li,
    inputdata: ul,
    close: txt
  });
  index++;
  
  //clique do close apenas definido para o elemento adicionado
  txt.onclick = function() {
      this.parentNode.parentNode.style.display="none";
  }
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>
  <form method="POST" action="">
    <label for="add-task">Título:</label>
    <input type="text" id="myInput" name="titulo">
    <label for="date">Prazo:</label>
    <input type="date" id="time" name="data" /><br><br>
    <span onclick="newElement();" class="addBtn" id="newtask" style="cursor:pointer">Add</span>
  </form>
  <div id="recent" class="recent">

  </div>
</body>

</html>

However, as I have already said in comments, constructing new html is much more simplified with strings. These strings save the entire html structure to add already with attributes and classes, and are applied directly to innerHTML.

Example with strings and innerHTML:

const inputText = document.getElementById("myInput");
const inputDate = document.getElementById("time");
const recent = document.getElementById("recent");

function newElement() {
  if (inputText.value === '') {
    alert("Você precisa digitar algo primeiro!");
    return;
  }
  
  let newHtml = `<div class="linha">
                   <input type="checkbox" class="checkIn" style="width:20px;">
                   <input type="text" value="${inputText.value}">
                   <input type="text" value="${inputDate.value}" style="width:90px;">               
                   <span><button class="close">\u00D7</button></span>
                 </div>`;
   recent.innerHTML += newHtml;
   
   for (let l of document.querySelectorAll(".linha .close")){
      l.onclick = function() {
        this.parentNode.parentNode.style.display="none";
      }
   }
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>
  <form method="POST" action="">
    <label for="add-task">Título:</label>
    <input type="text" id="myInput" name="titulo">
    <label for="date">Prazo:</label>
    <input type="date" id="time" name="data" /><br><br>
    <span onclick="newElement();" class="addBtn" id="newtask" style="cursor:pointer">Add</span>
  </form>
  <div id="recent" class="recent">

  </div>
</body>

</html>

In the latter case as the innerHTML is applied directly to <div id="recente"> it is necessary to re-apply the events of close to all lines.

  • Thank you for answering and for the link, because it was very enlightening.

0

The right thing is for you to create one container (or wrapper) (one div or a span, for example) for each item added. As you are doing, the elements are left without a reference of their own. See below the structure of how the added items are:

<div id="recent" class="recent">
  checkbox
  input texto
  input datepicker
  <span>
    botao X
  </span>

  checkbox
  input texto
  input datepicker
  <span>
    botao X
  </span>
</div>

Note that the items, which should belong to the same group, have as common reference only to div-pai id="recent", making the work complicated, because I am unable to select the child-elements that I want.

As mentioned, create a div to group the elements, thus:

<div id="recent" class="recent">
  <div class="itens">
    checkbox
    input texto
    input datepicker
    <span>
      botao X
    </span>
  </div>

  <div class="itens">
    checkbox
    input texto
    input datepicker
    <span>
      botao X
    </span>
  </div>
</div>

I made the changes commented on the function below:

function newElement() {
  var li = document.createElement("input");
  var ul = document.createElement("input");
  var done = document.createElement("input");
  var lista = document.createElement("div"); // criar uma div para agrupar os itens
  lista.setAttribute("class", "itens"); // atribuí uma classe à div
  done.setAttribute("type", "checkbox");
  var inputText = document.getElementById("myInput").value;
  var inputDate = document.getElementById("time").value;

  done.className = "checkIn";
  li.value = inputText;
  li.className = "valor";
  ul.value = inputDate;
  ul.className = "data";

  var span = document.createElement("SPAN");
  var txt = document.createElement("button");
  var xis = document.createTextNode("\u00D7");

  span.appendChild(txt);
  txt.appendChild(xis);
  txt.className = "close";

  if (inputText === '') {
    alert("Você precisa digitar algo primeiro!");
  } else {
    document.getElementById("recent").appendChild(lista); // adiciono a div à div-pai
    ultimo_item = document.getElementsByClassName("itens").length-1; // conto quantas divs possui e subtraio por 1 para pegar o index, que começa com 0
    document.getElementsByClassName("itens")[ultimo_item].appendChild(done).style.width = "20px"; // daqui pra baixo eu adiciono os elementos dentro da div
    document.getElementsByClassName("itens")[ultimo_item].appendChild(li);
    document.getElementsByClassName("itens")[ultimo_item].appendChild(ul).style.width = "90px";
    document.getElementsByClassName("itens")[ultimo_item].appendChild(span);

  }

  array.push({
    inputtexto: li,
    inputdata: ul,
    close: txt
  })
  index++;

  for (var i = 0; i < close.length; i++) {
    close[i].onclick = function() {
      var div = this.parentNode.parentNode; // seleciono o avô do span que oculta o item
      div.style.display = "none"; // oculto a div
    }
  }
}
  • Thank you for the reply

  • @Jessicakeilla You’re welcome! Obg!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.