Marcatectura
Marcatectura

Reputation: 1695

Retrieving multiple data-attributes and setting as text of a child element

Bottom Line:

I'm having trouble retrieving the value of multiple data-attributes and inserting them as the text of a child element.

Details:

I've got a table with each tr "bucket" containing a particular number of three kinds of shapes (spheres, cubes, pyramids), which are stored in data-attributes. I've got a ul with corresponding lis for each shape. When a shape is checked, trs with more than 0 of that shape are highlighted. HOWEVER, I'm also trying to retrieve the number for each selected shape and display it in the td.contents element for each tr (i.e. "pyramids: 300, cubes: 50"), which is what I have been unsuccessful with.

Here's the HTML -

<ul>
    <li data-shape="spheres">spheres</li>
    <li data-shape="cubes">cubes</li>
    <li data-shape="pyramids">pyramids</li>
</ul>

<table>
    <tr data-spheres="380" data-cubes="0" data-pyramids="200"><td>bucket 1</td><td class="contents">no shapes selected</td></tr>
    <tr data-spheres="0" data-cubes="90" data-pyramids="0"><td>bucket 2</td><td class="contents">no shapes selected</td></tr>
    <tr data-spheres="100" data-cubes="20" data-pyramids="400"><td>bucket 3</td><td class="contents">no shapes selected</td></tr>
    <tr data-spheres="500" data-cubes="110" data-pyramids="0"><td>bucket 4</td><td class="contents">no shapes selected</td></tr>
</table>

And JS (line 22 is where I'm having trouble) -

(function() {
//store tr elements
var buckets = $('tr');

  $('li').click(function () {
    //toggle checked class OK
    $(this).toggleClass('checked');
    //reset classes and .contents text OK
    $(buckets).removeClass('active');
    $('td.contents').text('no shapes selected');
    //map the shape data attribute for all li elements 
    //with class '.checked' OK
    var checkedShapes = $('.checked').map(function() {
        return $(this).data('shape');
    });
    //for each checked shape, filter tr elements with 
    //more than 0 of that shape OK 
    $.each(checkedShapes, function( index, value ) {
      var filteredBuckets = $(buckets).filter(function() {
        return $(this).data(value) > "0";
      });
      //add .active class to those tr elements OK
      $(filteredBuckets).addClass('active');
      //get number of checked shapes (i.e. "pyramids: 300, cubes: 50") 
      //and display in td.contents DOESN'T WORK
      $('tr.active td.contents').text($(this).parent('tr').data(value));
    });
  });

})();

And a jsFiddle: http://jsfiddle.net/a8gtrn63/33/

From what I understand in the docs for .data(), this should be retrieving the selected data attributes, but it isn't. I think there may be an issue with the value reference, but I'm having trouble seeing it. Any input is greatly appreciated.

Upvotes: 3

Views: 830

Answers (2)

Green
Green

Reputation: 111

The $(this) was referring to the $.each loop and not the text, so I fixed it by iterating through the elements and then used $(this):

(function() {
//store tr elements
var buckets = $('tr');

  $('li').click(function () {
    //toggle checked class OK
    $(this).toggleClass('checked');
    //reset classes and .contents text OK
    $(buckets).removeClass('active');
    $('td.contents').text('no shapes selected');
    //map the shape data attribute for all li elements 
    //with class '.checked' OK
    var checkedShapes = $('.checked').map(function() {
        return $(this).data('shape');
    });
    //for each checked shape, filter tr elements with 
    //more than 0 of that shape OK 
    $.each(checkedShapes, function( index, value ) {
      var filteredBuckets = $(buckets).filter(function() {
        return $(this).data(value) > "0";
      });
      //add .active class to those tr elements OK
      $(filteredBuckets).addClass('active');
      //get number of checked shapes (i.e. "pyramids: 300, cubes: 50") 
      //and display in td.contents DOESN'T WORK
      $('tr.active td.contents').each(function(){
         $(this).text($(this).parent('tr').data(value));
      });
    });
  });

})();

Upvotes: 1

Lajos Arpad
Lajos Arpad

Reputation: 76426

This is how your code should look alike:

(function() {
//store tr data-attributes
var buckets = $('tr');

  $('li').click(function () {
    //toggle checked class
    $(this).toggleClass('checked');
    //reset classes and .contents text
    $(buckets).removeClass('active');
    $('td.contents').text('no shapes selected');
    //map the shape data attribute for all li elements with class '.checked'
    var checkedShapes = $('.checked').map(function() {
        return $(this).data('shape');
    });
    //for each checked shape, filter tr elements with more than 0 of that shape
    $.each(checkedShapes, function( index, value ) {
      var filteredBuckets = $(buckets).filter(function() {
        return $(this).data(value) > "0";
      });
      //add .active class to those tr elements
      $(filteredBuckets).addClass('active');
      //get number of checked shapes and display in td.contents
      //$('tr.active td.contents').text($(this).parent('tr').data(value));
        $(filteredBuckets).each(function() {
            var currentText = $($(this).find("td")[1]).text();
            if (currentText.indexOf(":") === -1) {
                $($(this).find("td")[1]).text(value + ": " + $(this).data(value));
            } else {
                $($(this).find("td")[1]).text($($(this).find("td")[1]).text() + ", " + value + ": " + $(this).data(value));            }
        });
    });
  });

})();

Explanation: You need to iterate the filteredBuckets and set the desired text for each element. If it already has some shape data, then we append the new shape data and if there is no previous shape data, then we replace the old text to the new shape data.

Upvotes: 0

Related Questions