1

Situation: I am pulling data from a database and displaying it as a table on my website. When displayed, I am using nth-child(odd) and nth-child(even) to shade every other row to make it easier to see each row. I am using this multifilter JQuery plugin to filter the data by entering values into each input.

(function($) {
  "use strict";
  $.fn.multifilter = function(options) {
    var settings = $.extend( {
      'target'        : $('table'),
      'method'    : 'thead' // This can be thead or class
    }, options);

    jQuery.expr[":"].Contains = function(a, i, m) {
      return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
    };

    this.each(function() {
      var $this = $(this);
      var container = settings.target;
      var row_tag = 'tr';
      var item_tag = 'td';
      var rows = container.find($(row_tag));

      if (settings.method === 'thead') {
        // Match the data-col attribute to the text in the thead
        var col = container.find('th:Contains(' + $this.data('col') + ')');
        var col_index = container.find($('thead th')).index(col);
      };

      if (settings.method === 'class') {
        // Match the data-col attribute to the class on each column
        var col = rows.first().find('td.' + $this.data('col') + '');
        var col_index = rows.first().find('td').index(col);
      };

      $this.change(function() {
        var filter = $this.val();
        rows.each(function() {
          var row = $(this);
          var cell = $(row.children(item_tag)[col_index]);
          if (filter) {
            if (cell.text().toLowerCase().indexOf(filter.toLowerCase()) !== -1) {
              cell.attr('data-filtered', 'positive');
            } else {
              cell.attr('data-filtered', 'negative');
            }
            if (row.find(item_tag + "[data-filtered=negative]").size() > 0) {
               row.hide();
            } else {
              if (row.find(item_tag + "[data-filtered=positive]").size() > 0) {
                row.show();
              }
            }
          } else {
            cell.attr('data-filtered', 'positive');
            if (row.find(item_tag + "[data-filtered=negative]").size() > 0) {
              row.hide();
            } else {
              if (row.find(item_tag + "[data-filtered=positive]").size() > 0) {
                row.show();
              }
            }
          }
        });
        return false;
      }).keyup(function() {
        $this.change();
      });
    });
  };
})(jQuery);

When the table is created, each <tr> tag's css is set to display: contents; by default. When I filter the data, the <tr> tag's display is then changed to none. All of my css is written in an external file in sass. The sass for the nth-child looks like this:

tr:nth-child(even) {
    background-color: $tableHighlight1; // rgb(236, 236, 236)
    @media only screen and (min-device-width : 400px) {
        background: none;
    }
}

tr:nth-child(odd) {
    background-color: $tableHighlight2; // white
    @media only screen and (min-device-width : 400px) {
        background: none;
    }
}

When the table is created it looks great with the rows separated every other by color. For example:

enter image description here

But when I filter the data, because the rows are assigned their color when the DOM is created, there is a chance that rows with the same color will line up and it looks really bad.

enter image description here

I need to know how I can control this whether it be css, scss, javascript, jquery, etc. For reference, I am using php as my backend. The code to create my table looks like this:

                     $result = $con->query($query);
                     echo "<table id='vendor-table' class='vendors'>";
                     echo "<thead>";
                     echo "<tr>";
                     echo "<th data-type='text-short'>Status</th>";
                     echo "<th data-type='numeric'>Vendor AP ID</th>";
                     echo "<th data-type='text-long'>Vendor Name</th>";
                     echo "<th data-type='text-long'>Alternate Name</th>";
                     echo "<th data-type='text-long'>Invoice Name</th>";
                     echo "</tr>";
                     echo "</thead>";
                     echo "<tbody>";
                     while($row = $result->fetch_assoc()) {
                        echo "<tr>"; 
                        echo "<td data-title='Status' class='row'>".$row["status"]."</td>";
                        echo "<td data-title='Vendor AP ID' class='row'>".$row["vendor_ap_id"]."</td>";
                        echo "<td data-title='Vendor Name' class='row'>".$row["vendor_name"]."</td>"; 
                        echo "<td data-title='Alternative Name' class='row'>".$row["Alternate_Name"]."</td>";
                        echo "<td data-title='Invoice Name' class='row'>".$row["Invoice_Name"]."</td>";
                        echo "</tr>";
                     }
                     echo "</tbody>";
                     echo "</table>";
                  }

My jquery that I am using to call the multifilter.js plugin looks like this:

            $(document).ready(function() {
               $('.filter').multifilter();
            });

If anyone has any sources or knowledge on how I can update the css to cover just the left over rows displayed as contents, I would be very grateful. Thank you. I hope I left enough information to help you understand my question. Let me know if I need to clarify anything.

1 Answers1

1

I don't think what you're trying to achieve is possible with CSS only. The best solution would be to use row.detach() to remove the table row and append it whenever needed instead of using row.hide() and row.show() as shown in your code.

This solution from Joseph Marikle might help you understand this better: How to toggle elements in and out of DOM using jQuery detach() method?

Sangam BK
  • 28
  • 6
  • This is great, @sangambk! I think this is what I am looking for. However, I didn't write the jquery plugin and I am new to it so I don't exactly know how to implement the method to append it back into the table in this case. Where the code says row.hide() I will replace with row.detach() but I am unsure how to reappend it. – DataMuncher Jun 23 '21 at 20:29