skip to Main Content

I have a view in django that utilizes jQuery to retrieve some data from the backend once the user selects some filter options. After the data is retrieved I’m dynamically creating table rows and appending them to the table body. Each row contains data about a release, each release has a unique ID. I would like if the user clicked on any cell in a row, for it to navigate to another page with more information about the release, below is how I’m building the table:

    function updateTable(filtered_releases) {
        var table_body = document.getElementById("release-table-body");

        // append the new data to the table body
        console.log("STARTING TO ADD RELEASES TO NEW TABLE BODY");
        for (const release in filtered_releases) {
            // get all the variables for the release
            var new_release = filtered_releases[release];
            var id = new_release['id'];
            var release_type = new_release['release_type'];
            var business_unit = new_release['business_unit'];
            var product_line = new_release['product_line'];
            var product_id = new_release['product_id'];
            var deployment_project = release_type == "github" ? new_release['repo_name'] : new_release['deployment_project'];
            var deployment_environment = new_release['deployment_environment'];
            var deployment_version = new_release['version'];

            // create the new row
            var new_row = document.createElement("tr");
            new_row.id = "release_" + id;

            // checkbox
            var td_checkbox = document.createElement("td");
            var checkbox = document.createElement("input");
            checkbox.type = "checkbox";
            td_checkbox.appendChild(checkbox);
            new_row.appendChild(td_checkbox);

            // id
            var td_id = document.createElement("td");
            td_id.innerHTML = id;
            td_id.addEventListener("click", function () { navigateToDeploymentView(id) });
            new_row.appendChild(td_id);

            // release_type
            var td_release_type = document.createElement("td");
            td_release_type.innerHTML = release_type;
            td_release_type.addEventListener("click", function () { navigateToDeploymentView(id) });
            new_row.appendChild(td_release_type);

            // business_unit
            var td_business_unit = document.createElement("td");
            td_business_unit.innerHTML = business_unit;
            td_business_unit.addEventListener("click", function () { navigateToDeploymentView(id) });
            new_row.appendChild(td_business_unit);

            // product_line
            var td_product_line = document.createElement("td");
            td_product_line.innerHTML = product_line;
            td_product_line.addEventListener("click", function () { navigateToDeploymentView(id) });
            new_row.appendChild(td_product_line);

            // product_id
            var td_product_id = document.createElement("td");
            td_product_id.innerHTML = product_id;
            td_product_id.addEventListener("click", function () { navigateToDeploymentView(id) });
            new_row.appendChild(td_product_id);

            // deployment_project
            var td_deployment_project = document.createElement("td");
            td_deployment_project.innerHTML = deployment_project;
            td_deployment_project.addEventListener("click", function () { navigateToDeploymentView(id) });
            new_row.appendChild(td_deployment_project);

            // deployment_environment
            var td_deployment_environment = document.createElement("td");
            td_deployment_environment.innerHTML = deployment_environment;
            td_deployment_environment.addEventListener("click", function () { navigateToDeploymentView(id) });
            new_row.appendChild(td_deployment_environment);

            // version
            var td_version = document.createElement("td");
            td_version.innerHTML = deployment_version;
            td_version.addEventListener("click", function () { navigateToDeploymentView(id) });
            new_row.appendChild(td_version);

            // append this new row to the table body
            table_body.appendChild(new_row);
        }
        console.log("FINISHED ADDING RELEASES TO NEW TABLE BODY");
    }

For each cell in the rows I’m assigning the following onclick function, that accepts the id of the release which is assigned when I dynamically create the rows.

    function navigateToDeploymentView(id) {
        window.location = '{{ base_url }}/deployment/?id=' + id;
    }

However once the table is rendered, no matter what row I click on it will always take me to the page correlating to the ID of the last entry. So in this example image, no matter what cell I click on for entries 467 and 468, it will direct me to the page with data about entry 469. So it seems the ‘id’ variable is being updated for all entries after the for loop makes its last iteration. Not sure how to fix this.

I tried setting up the onclick function in the following 2 other ways:

// way 1
td_id.addEventListener("click", function () { 
  window.location = '{{ base_url }}/deployment/?id=' + id;
 });

// way 2
td_id.onclick = function () {navigateToDeploymentView(id)}

I also tried a workaround where I would set each cells id equal to the release id, and passing in the cell to the function so I can access it’s id that way, but it would still only pass in the data from the very last row.

3

Answers


  1. You can try to add data attribute with the id of release on tr and get data attribute value of clicked element. Inspect HTML to see if id are on data attribute.

    new_row .setAttribute('release-id', id) ;
    new_row .addEventListener("click", function () { 
          window.location = '{{ base_url }}/deployment/?id=' + this.getAttribute('release-id');
         });
    
    Login or Signup to reply.
  2. It’s far better to store that ID value as a dataset and access it on the click. Plus, rather than set a bunch of different listeners for the same thing, just use another data attribute to signify which ones should get the listener.

    document.querySelectorAll('[data-linked]').forEach(d => {
      d.addEventListener('click', e => {
        console.log(`clicked on ${e.target.dataset.id}`);
      })
    })
    <table>
      <tr>
        <td data-linked data-id='123'>123</td>
        <td data-linked data-id='456'>456</td>
        <td data-linked data-id='789'>789</td>
      </tr>
    </table>
    Login or Signup to reply.
  3. You identified the problem. That is, no matter what row you click on, it always takes you to the page correlating to the id of the last entry. Your theory of probable cause is not correct. It is not that the loop updates all entries on its last iteration one last time. The id is always overwritten with the current id in the loop until it reaches its last id. Indeed, the id will always be the lastest in this situation. Remember, given that there is no state, you must write the id as an HTML attribute to the HTML tag. Then retrieve that id in your navigateToDeploymentView function. You can use the .data() method to retrieve HTML data attributes on every click consequently passing the correct id each time a row is clicked on.

    Here is a plan of action to resolve the problem:

    • Add element.setAttribute(name, value) where name is data-id and value is new_release[‘id’]. If you view the source in Chrome, every input checkbox should have data-id="some-id-here".

    • Retrieve data-id in the function navigateToDeploymentView() with $( element ).data( "id" ); Finally, use the newly retrieved id in your window.location.

    I hope this helps.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search