Get values from mulitple checkboxes on different table rows

Question

I have two table rows each containing 3 checkboxes, each within a <td>.

I want to display a fourth <td> within that row depending on certain rules of which checkbox is checked. Each row is like this:

HTML

<tr class="tableRow">
    <td>
       <input class="select" class="select" type="checkbox" value="select"/>
    </td>
    <td>
       <input class="voice" class="voice" type="checkbox" value="voice">
    </td>
    <td>
       <input class="mail" class="mail" type="checkbox" value="mail"/>
    </td>

    <!--The <td>'s i want the results of the checkboxes to show -->
    <td class="initial-cost">Initial cost</td> 

    <td class="voicemail-and-initial-cost">VoiceMail and Initial Cost</td>

    <td class="email-and-initial-cost">Email and Initial Cost</td>

    <td class="all-services-cost">All Services Cost</td>  
</tr>

And I have this jQuery which kinda works but it shows all the table rows' '...cost' 's rather than for each row individually

jQuery

$(document).ready(function() {                 //on page load....
$(".voicemail-and-initial-cost").hide();   //hide all cost elements
$(".email-and-initial-cost").hide();       //hide all cost elements
$(".all-services-cost").hide();                //hide all cost elements


$(".select").change(function(event) {              //when #select is clicked...
    if ($(this).is(":checked")) {                  //if this checkbox has been checked...
        $(".initial-cost").show();                 //show .initial-cost element
    } else {                                        //otherwise...
        $(".voicemail-and-initial-cost").hide();   //hide all cost elements
        $(".email-and-initial-cost").hide();       //hide all cost elements
        $(".all-services-cost").hide();                //hide all cost elements
    }
});

$(".voice").change(function(event) {                   //when #voice is clicked...
    if ($(this).is(":checked")) {                      //if this checkbox has been checked...
        if ($('.mail').is(":checked")) {               //check to see if #mail is checked too and if it is...
            $(".initial-cost").hide();                 //hide .initial-cost
            $(".voicemail-and-initial-cost").hide();   //hide .voicemail-and-initial-cost
            $(".email-and-initial-cost").hide();
            $(".all-services-cost").show();            //show .all-services-cost
        } else {                                        //but if #mail is not checked....
            $(".initial-cost").hide();                 //hide .initial-cost
            $(".voicemail-and-initial-cost").show();   //show .voicemail-and-initial-cost instead
        }
    } else {                                                                            //otherwise if this checkbox is not checked...
        if(($('.select').is(":checked")) && ($('#mail').is(":checked"))){             //and .select AND .mail is checked however...
            $(".initial-cost").hide();                                                 //hide .initial-cost
            $(".all-services-cost").hide();                                                // hide .all-services-cost
            $(".email-and-initial-cost").show();                                       //show .email-and-initial-cost instead
        } else if (($('.select').is(":checked")) && (!$('.mail').is(":checked"))){        //otherwise if #select is checked AND #mail is NOT checked....
            $(".voicemail-and-initial-cost").hide();
            $(".initial-cost").show(); 
        }
    }
});

$(".mail").change(function(event) {                        //when #mail is clicked...
    if ($(this).is(":checked")) {                      //if this checkbox has been checked...
        if ($('.voice').is(":checked")) {              //check to see if #voice is checked too and if it is...
            $(".initial-cost").hide();                 //hide .initial-cost
            $(".voicemail-and-initial-cost").hide();   //hide .voicemail-and-initial-cost
            $(".email-and-initial-cost").hide();       //hide .email-and-initial-cost
            $(".all-services-cost").show();            //show .all-services-cost
        } else {                                        //but if #voice is not checked....
            $(".initial-cost").hide();                 //hide .initial-cost
            $(".email-and-initial-cost").show();       //show .email-and-initial-cost instead
        }
    } else {                                                                            //otherwise if this checkbox is not checked...
        if(($('.select').is(":checked")) && ($('.voice').is(":checked"))){                //and #select and #voice is checked however...
            $(".all-services-cost").hide();                                                // hide .all-services-cost
            $(".voicemail-and-initial-cost").show();                                   //show .voicemail-and-initial-cost
        } else if (($('.select').is(":checked")) && (!$('.voice').is(":checked"))){       //if this checkbox is not checked AND #voice is NOT checked...
            $(".all-services-cost").hide();                                                // hide .all-services-cost
            $(".voicemail-and-initial-cost").hide();
            $(".email-and-initial-cost").hide(); 
            $(".initial-cost").show();                                     //show .initial-cost instead
        }

    }
});
}); //end of ready

Now I figured to target just the elements of the row in question, I would have to change the jquery selectors from what is here:

 $(".initial-cost").hide();

to something like:

 $('td').next(':has(.initial-cost):first').hide();

But now I get nothing happening at all - not even any error messages in the console.

Please note its not the rules themselves that is the problem, its the fact I want those rules to only apply per table row, not all of them at once. I hope this makes sense and someone out there that point me in the right direction. here is a JSfiddle of what I have should it help: https://jsfiddle.net/monkeyroboninja/5n0v0eL5/


Show source
| jquery   | html   2017-01-03 16:01 3 Answers

Answers ( 3 )

  1. 2017-01-03 16:01

    Changes lines like this:

    $(".initial-cost").show();  
    

    To

    $(this).parents('.tableRow').find(".initial-cost").show();  
    

    Which correctly target another element in the same row as the changed checkbox element.

  2. 2017-01-03 17:01

    This is what I would do. I only post the essential.

    Use the data- attribute to read data; there are many other tricks, but I like this one.

    (notice, Jamiec uses the same principle: look for parent, ...)

    <style>
      td.apples, td.pears, td.lemons {
        visibility: hidden;
      }
    </style>
    <table>
      <tr>
        <td>
          <input class="check" data-fruit="apples"  type="checkbox"> apples
        </td>
        <td>
          <input class="check" data-fruit="pears" type="checkbox"> pears
        </td>
        <td>
          <input class="check" data-fruit="lemons" type="checkbox"> lemons
        </td>
        <td class="apples">
          I like apples
        </td>
        <td class="pears">
          I like pears
        </td>
        <td class="lemons">
          I like lemons
        </td>
      </tr>
      <tr>
        <td>
          <input class="check" data-fruit="apples"  type="checkbox"> apples
        </td>
        <td>
          <input class="check" data-fruit="pears" type="checkbox"> pears
        </td>
        <td>
          <input class="check" data-fruit="lemons" type="checkbox"> lemons
        </td>
        <td class="apples">
          I like apples (2)
        </td>
        <td class="pears">
          I like pears (2)
        </td>
        <td class="lemons">
          I like lemons (2)
        </td>
      </tr>
    </table>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script>
      $(document).ready(function() {
        // event.  click on one of the checkboxes
        $('.check').change(function(e) {
          // on or off?
          var on_off = $(this).is(":checked") ? true : false;   // heredoc notation
          // we read the data-fruit attribute
          var fruit = $(this).data('fruit');
          // now we want to know which row this is, so we find the parent
          var parent_row = $(this).parents('tr');
          // we have the parent, so we can look for children that have the same class as the data-fruit
          var cel = parent_row.find('.' + fruit).css('visibility', on_off ? 'visible' : 'hidden');
        })
      })
    </script>
    
  3. 2017-01-03 17:01

    You can drastically simplify your code by encoding the 'rules' of checkbox states. You have 3 check-boxes which gives you 8 (2^3) possibilities. You can capture all these up-front in an object literal and just refer to them in the event handler.

    The event handler need only check for a change to state; recompute the state; and check the object to see what to display.

    To work on an individual row you just get the closest <tr> to the <input> that was changed.

    So your code can be simplified to this:

    var userOptionState = {
      0: 'No cost',
      1: 'Initial cost',
      2: 'Voice cost',
      3: 'Initial and voice cost',
      4: 'Mail cost',
      5: 'Initial and mail cost',
      6: 'Voice and mail cost',
      7: 'Initial and voice and mail cost'
    };
    
    $(document).ready(function() {
      $(".select, .voice, .mail").change(function(event) { 
        var sum = 0;
        var row = $(this).closest('tr');
        if(row.find('td input.select').is(':checked')) {sum += 1}
        if(row.find('td input.voice').is(':checked')) {sum += 2}
        if(row.find('td input.mail').is(':checked')) {sum += 4}
        row.find('td.out').html(userOptionState[sum]);
      });
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <table>
      <tbody>
        <tr class="tableRow">
          <td>
            <input class="select" type="checkbox" value="select" />
          </td>
          <td>
            <input class="voice" type="checkbox" value="voice">
          </td>
          <td>
            <input class="mail" type="checkbox" value="mail" />
          </td>
          <!--output td -->
          <td class="out">No cost</td>
        </tr>
        <tr class="tableRow">
          <td>
            <input class="select" type="checkbox" value="select" />
          </td>
          <td>
            <input class="voice" type="checkbox" value="voice">
          </td>
          <td>
            <input class="mail" type="checkbox" value="mail" />
          </td>
          <!--output td -->
          <td class="out">No cost</td>
        </tr>
      </tbody>
    </table>

◀ Go back