1

I have a table of products ordered by the value of the last column of each row. I want that when I click on an input, the corresponding checkbox change directly to selected. In this way, when I click on the Save button, only the selected products will be managed to update in the database.

The original code has too many things that are not related to the question, so I have reduced it to this:

var c = 10;
var count = 1;
pageList.forEach(element => {
    document.getElementById("tabla_variantes").innerHTML+=`
        <tr style="background: white;">
            <th class="check_col" scope="row" style="padding: 0px; text-align: center; vertical-align: middle;">
                <input type="checkbox" value="${element.numero}" id="row${count}" name="row-check-pro">
            </th>
            <td> //image </td>
            <td> //product number </td>
            <td> //product name </td>
            <td> //product reference </td>
            <td> //product price </td>
            <td> //product stock </td>
            <td style="text-align:center; vertical-align: middle; padding: 8px 18px;">
                <input type="text" class="form-control text-end" id="posicion${element.numero}" value="${c}">
            </td>
        </tr>
    `;
    document.getElementById(`posicion${element.numero}`).addEventListener('input', (evt) => {
        console.log('run'); // Do something
        document.getElementById("row"+count).checked = true;
    });
    ++count;
    c += 10;
    if (c > list.length*10) c = 10;
});

As you can see I have tried to add a listener to each input, but nothing is showing on the console.

2 Answers 2

3

You REALLY should delegate

Also I suggest using map instead of concatenating to the DOM.

This is a drop in replace

const container = document.getElementById("tabla_variantes");
const pageList = [{numero:1},{numero:2},{numero:3}];

container.addEventListener('input', (evt) => {
  const tgt = evt.target; 
  if (tgt.name==="row-check-pro") {
    if (!tgt.checked) tgt.closest("tr").querySelector(".text-end").value="";
  }  
  if (tgt.classList.contains("text-end")) {
    tgt.closest("tr").querySelector("[name=row-check-pro]").checked = tgt.value.trim() != ""; 
  }  
});


var c = 10;
var count = 1;
container.innerHTML+= pageList.map(element => {
  const str = `<tr style="background: white;">
            <th class="check_col" scope="row" style="padding: 0px; text-align: center; vertical-align: middle;">
                <input type="checkbox" value="${element.numero}" id="row${count}" name="row-check-pro">
            </th>
            <td style="text-align:center; vertical-align: middle; padding: 8px 18px;">
                <input type="text" class="form-control text-end" id="posicion${element.numero}" value="${c}">
            </td>
        </tr>
    `;
    ++count;
    c += 10;
    if (c > pageList.length*10) c = 10;
    return str;
}).join("");
<table id="tabla_variantes">
</table>

Sign up to request clarification or add additional context in comments.

18 Comments

You don't need to, but you probably should. :-)
@FaridShokri - Certainly in some cases. Here the OP seems to want to completely replace the contents of the target element, so building up one string and passing just one complete string to the browser to parse and build the entire structure in one go probably makes more sense.
@EmiliBellotPulido this IS delegation: container.addEventListener('input', (evt) => { const tgt = evt.target; tgt.closest("tr").querySelector("[name=row-check-pro]").checked = true;}); - I delegate the click from the container, so any element in the container can detect the input and it will be processed as above. You can add to this function by testing the tgt.tagName or classList
That is what tgt.closest("tr") does - access the closest tr of the target input field and find the checkbox from there
@EmiliBellotPulido - Where I said you should consider "event delegation and DOM traversal," the event delegation here is handling the click on container, and the DOM traversal is the tgt.closest("tr").querySelector(...) part. :-)
|
1

The main problem is that you're using += with innerHTML. That's never a good idea. When you do x.innerHTML += str, the browser has to work through all of the elements within the x element, build an HTML string, return that string to the JavaScript code, then accept the updated string from the JavaScript code, tear down all the previous child elements of x, and replace them with new child elements created by parsing the new string. All state for those elements is lost, including any event handlers they have on them.

The minimal change is to:

  1. Build up all the HTML in a string variable
  2. Assign it to innerHTML
  3. Find the elements and add event handlers to them

But you should consider using event delegation and DOM traversal rather than handlers on each individual element. More about event delegation in this answer on Stack Overflow, but the short version is you handle the event on a common ancestor element, then use event.target to determine what descendant was targeted by the event.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.