0

I want to add a checkbox to each row of a table. All will be selected originally, then have the ability to check/uncheck to filter the rows of data.

There is a similar question here but I don't know how to implement. I'm a bit of a newbie here.

Here is my code that generates the table:

function init() {

     // Get scenario names
     var selector = d3.select("#selDataset");

     // d3.csv("data/final/hou_scenarios.csv").then(annualData => {
     //      console.log(annualData);
     //      console.log(annualData[0]["Scenario"]);




     // Populate the annual table
     d3.csv("data/final/hou_annual_data.csv").then(annualData => {
          console.log("ANNUAL DATA");
          console.log(annualData);
          console.log(annualData[0]["Scenario"]);

          var tableAnnualData = annualData;

          // reference table body
          var tbody = d3.select("tbody");

          // use Arrow Functions to loop through the object (each dictionary) "scenario" and append to table row
          // use fat arrow method to iterate over objects and then the key:value pairs
          annualData.forEach((scenario) => {
               var row = tbody.append("tr");
               Object.entries(scenario).forEach(([key, value]) => {
                    var cell = row.append("td");
                    cell.text(value);
               });
               // verify objects
               console.log("VERIFY LOOPED DATA");
               console.log(scenario);
          });


          var scenarios = annualData.map(o => o.Scenario)
          console.log("SCENARIO NAMES");
          console.log(scenarios);

          scenarios.forEach(scenario => {
               selector.append("option")
                    .text(scenario)
                    .property("value", scenario);
          });

     });
}

init();

The table is rendering just fine. What I want to do is add checkboxes next to the first column to be able to turn rows on/off from displaying.

screen shot of what I want

Any suggestions on what to do? The checkboxes could be the first table row. Or they could be in there own css container, though I would prefer them as part of the table.

1
  • How would a row be turned on when it is not being displayed? Commented Jun 24, 2021 at 21:50

1 Answer 1

0

Here is an example of how this might be performed without having access to your CSV file.

Basically you need to locate the section that creates the rows for the tbody where your cells for each row are created, create a button, you can add ids or a dataset attribute on each button to use for toggling your buttons content. Once your button is created and you assign the attributes and/or classes you want, wrap it in a data cell td, create the td cell just as you did the button and append it to the row.

I have added detailed info within the snippit that covers pretty much every detail of creating the button, appending it, and hiding the content.

const people = [{
    id: 35431,
    firstName: 'Billy',
    lastName: 'Kid',
    status: 'pass',
    score: 74
  },
  {
    id: 90974,
    firstName: 'John',
    lastName: 'Doe',
    status: 'pass',
    score: 98
  },
  {
    id: 68952,
    firstName: 'Jane',
    lastName: 'Doe',
    status: 'fail',
    score: 57
  },
  {
    id: 45283,
    firstName: 'Bob',
    lastName: 'Dobbs',
    status: 'pass',
    score: 87
  },
  {
    id: 53425,
    firstName: 'Jean',
    lastName: 'White',
    status: 'pass',
    score: 90
  }
]
// basic function to create a table using data from an array of objects
function createTable() {
  const cont = document.getElementById('cont')
  const table = document.createElement('TABLE')
  const thead = document.createElement('THEAD')
  const row = document.createElement('TR')
  const tbody = document.createElement('TBODY')
  cont.append(table)
  table.append(thead)
  thead.append(row)
  table.border = '1'
  for (index in people[0]) {
    let th = document.createElement('TH')
    th.textContent = index
    row.append(th)
  }
  table.append(tbody)
  // we will now iterate over our array of objects and build our table body content
  for (value in people) {
    // create a tr row for each 'person` in our array of objects
    const dataRow = document.createElement('TR')
    // now lets iterate over our objects to get the values of each person
    for (person in people[value]) {
      // create a data cell to hold the content
      let td = document.createElement('TD')
      // set textContent to each of our objects values
      td.textContent = people[value][person]
      // append the data cells to the row
      dataRow.append(td)
    }
    // now to create and add the button
    let btn = document.createElement('BUTTON')
    // set the name as a data-set attribute on button this will 
    // be used for toggling name in another function
    btn.dataset.name = people[value].firstName
    // set default text for buttons textContent
    btn.textContent = `Hide ${people[value].firstName}` 
    // add a class used for CSS to NOT target this element when hidden
    btn.classList.add('remove-option')
    // lets wrap this button in a TD cell for HTML table validation
    let buttonCell = document.createElement('TD')
    // append btn to td
    buttonCell.append(btn)
    // append td to tbody
    dataRow.append(buttonCell)
    tbody.append(dataRow)
  }
}

// here is where we hide the elements on click of the button
function hideLine(e){ // pass in the event target from click listener
  // get the parent which will be the table row tag <tr>
  const parent = e.target.parentNode.parentNode
  // define a variable that gets only the td tags within this parent element
  let td = parent.querySelectorAll('td')
  // iterate over the td elements and define each one as a variable "cell"
  td.forEach(cell => {
    // toggle a class called hide on click
    cell.classList.toggle('hide')
    // check to see if our event.target elements class list 
    // contains the hidden class, this way we can also toggle
    // buttons text to match our current state hide or show
    cell.classList.contains('hide') ?
      e.target.textContent = `Show ${e.target.dataset.name}` :
      e.target.textContent = `Hide ${e.target.dataset.name}`
   })  
}

createTable()

const removeBtn = document.querySelectorAll('.remove-option')
removeBtn.forEach( btn => {
  btn.addEventListener('click', hideLine)
})
.hide:not(:last-child) {
  visibility: hidden;
}

td, th {
  padding: .3rem 1rem;
}
<div id="cont"></div>

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

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.