Search code examples
javascriptjquerytablesorter

Issues using textExtraction with jQuery tablesorter


I am attempting to sort a table column containing some text and a date by date. I have put a hidden span in front the cells containing only the date and use textExtraction to get the date so that I can then sort using sorter:"shortDate". However when I click on the header nothing happens.

I have tested the code on jsFiddle and it works which makes this all the more surprising to me. Any ideas on what might be causing this would be greatly appreciated.

The JS:

 function dataTable(table) {
$(table).addClass('ui-widget tablesorter');
$(table).children('thead').addClass('ui-widget-header');
$(table).children('tbody').addClass('ui-widget-content');
$(table).children('tbody').children('tr').hover(
    function(){$(this).addClass('ui-state-hover');},
    function(){$(this).removeClass('ui-state-hover');}
);
}

$(document).ready(function () {
$('.dataTable').each(function() {
    dataTable($(this));
});
});

$(document).ready(function(){ 
        $('.dataTable').tablesorter({
             widgets: ['staticRow'],
             dateFormat: 'ddmmyyyy',
             textExtraction: {7 : function(node) {
                    return $(node).find("span").text(); 
                    }
             },
             headers:{
                5:{sorter: "shortDate"},
                7:{sorter: "shortDate"}
             }
        }); 
        $(".dataTable").data('tablesorter').sortList = [[7,1]];
        $(".dataTable").trigger('update');
    });

The HTML:

<table class="dataTable" border="1" style="border-collapse:collapse">
        <thead>
            <tr><th>Version</th><th>Lot</th><th>Lot N°</th><th>Environnement</th><th>Créateur</th><th>Date de création</th><th>Planification</th><th>Etat</th></tr>
        </thead>
        <tbody id="searchable">
            <c:forEach var="version" items="${demandes}" varStatus="status">
            <c:forEach var="demandeInstallation" items="${version}" varStatus="status2">
                <tr>
                <td><c:out value="${livrables[status.index].version}"></c:out></td>
                <td><c:out value='${demandeInstallation.lot}'/></td>
                    <td><fmt:formatNumber value="${demandeInstallation.numeroLot}" pattern="0000"/></td>
                    <td><c:out value='${demandeInstallation.environnement}'/></td>
                    <td><c:out value='${demandeInstallation.demandeur}'/></td>
                    <td><fmt:formatDate value="${demandeInstallation.date}" pattern="dd/MM/yyyy HH:mm"/></td>
                    <td>
                    <c:if test="${!empty demandeInstallation.planification}">
                    <fmt:formatNumber value="${demandeInstallation.planification div 60}" pattern="##"/>:<fmt:formatNumber value="${demandeInstallation.planification mod 60}" pattern="00"/>
                    </c:if>
                    </td>
                    <c:if test="${!empty demandeInstallation.etat.etat}">
                    <td class="etatDemande_${demandeInstallation.etat.etat}"><fmt:formatDate value="${demandeInstallation.etat.createdOn}" pattern="dd/MM/yyyy HH:mm" var="createdOn"/><span style="display:none"><c:out value="${createdOn}"/></span><s:message code="EtatDemande.${demandeInstallation.etat.etat}" arguments="${createdOn}, ${demandeInstallation.etat.createdBy}"/></td>
                    </c:if>
                </tr>
            </c:forEach>
            </c:forEach>
        </tbody>
    </table>
    <script type="text/javascript" src="<s:url value="/js/searchbar.js"/>"></script>
</body>

Edit: The code for searchBar.js:

var $rows,$pageNumber,$rowsPerPage;
$('#searchBar').keyup(function() {
  var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase().split(' ');

  $rows.hide().filter(function() {
    var text = $(this).text().replace(/\s+/g, ' ').toLowerCase();
    var matchesSearch = true;
    $(val).each(function(index, value) {
      matchesSearch = (!matchesSearch) ? false : ~text.indexOf(value);
    });
    return matchesSearch;
  }).show();

  var j = $pageNumber * $rowsPerPage;
  for (i = 0; i < $rows.length; i++){
      if($rows.eq(i).is(':visible') && j < $rowsPerPage*($pageNumber + 1)){
          j++;
      }
      else{
          $rows.eq(i).hide();
      }
  }
  if (j < $rowsPerPage){
      $('#moreResults').hide();
  }
  else{
      $('#moreResults').show();
  }
  $('#searchTextField').val($(this).val());
});

$(document).ready(function(){
    /*for (i = 0; i < $rows.length ; i++){
        if (i < $pageNumber*$rowsPerPage || i >= $rowsPerPage*($pageNumber + 1))
        {
            $rows.eq(i).hide();
        }   
    }*/
    $rows = $('#searchable tr');
    $pageNumber = $('#pageNumber').val();
    $rowsPerPage = $('#rowsPerPage').val();
    $('#searchBar').val($('#searchTextField').val());
    $('#searchBar').keyup();
});

Edit 2

I used the debug and found that I was initializing the tablesorter a second time which doesn't work so I changed my code to:

$(document).ready(function () {
         $(".dataTable").data('tablesorter').debug = true;
         $(".dataTable").data('tablesorter').textExtraction = {7: function(node) {return $(node).find("span").text();}};
         $(".dataTable").data('tablesorter').headers = {5: { sorter: "shortDate" },7: { sorter: "shortDate" }};
         $(".dataTable").data('tablesorter').sortList = [[7,1]];
         $(".dataTable").trigger('update');
    }); 

Console output: It appears that the text extraction isn't being applied as the contents of column 7 are still in the form "date text date text" instead of just the first date.

Debug log


Solution

  • Having found no way to make textExtraction work on my page, the solution I came up with was to put a hidden column containing only the date to sort on before the column I want to display.

    The result looks like this :

    In a separate file "dataTable.js" included in the head, the code to initialize tableSorter for any table of the class tablesorter:

    $(document).ready(function () {
        $('.dataTable').tablesorter({
             widgets: ['staticRow'],
             dateFormat: 'ddmmyyyy'  
         }); 
    });
    

    In the jsp containing the problematic table:

    <head>
        <title>Historique</title>
        <%@ include file="/head.jsp" %><!-- This is where dataTable.js is included-->
        <script type="text/javascript">
            $(document).ready(function () {
                $(".dataTable").data('tablesorter').sortList = [[7,1]];
                $(".dataTable").trigger('update');
            });
        </script>
    </head>
    <body>
        <table class="dataTable" border="1" style="border-collapse:collapse">
            <thead>
                <tr><th>Version</th><th>Lot</th><th>Lot N°</th><th>Environnement</th><th>Créateur</th><th>Date de création</th><th>Planification</th><th colspan="2">Etat</th></tr>
            </thead>
            <tbody id="searchable">
                <c:forEach var="version" items="${demandes}" varStatus="status">
                <c:forEach var="demandeInstallation" items="${version}" varStatus="status2">
                    <tr>
                    <td><c:out value="${livrables[status.index].version}"></c:out></td>
                    <td><c:out value='${demandeInstallation.lot}'/></td>
                        <td><fmt:formatNumber value="${demandeInstallation.numeroLot}" pattern="0000"/></td>
                        <td><c:out value='${demandeInstallation.environnement}'/></td>
                        <td><c:out value='${demandeInstallation.demandeur}'/></td>
                        <td><fmt:formatDate value="${demandeInstallation.date}" pattern="dd/MM/yyyy HH:mm"/></td>
                        <td>
                        <c:if test="${!empty demandeInstallation.planification}">
                        <fmt:formatNumber value="${demandeInstallation.planification div 60}" pattern="##"/>:<fmt:formatNumber value="${demandeInstallation.planification mod 60}" pattern="00"/>
                        </c:if>
                        </td>
                        <c:if test="${!empty demandeInstallation.etat.etat}">
                        <td style="display:none"><fmt:formatDate value="${demandeInstallation.etat.createdOn}" pattern="dd/MM/yyyy HH:mm"/></td>
                        <td class="etatDemande_${demandeInstallation.etat.etat}"><fmt:formatDate value="${demandeInstallation.etat.createdOn}" pattern="dd/MM/yyyy HH:mm" var="createdOn"/><s:message code="EtatDemande.${demandeInstallation.etat.etat}" arguments="${createdOn}, ${demandeInstallation.etat.createdBy}"/></td>
                        </c:if>
                    </tr>
                </c:forEach>
                </c:forEach>
            </tbody>
        </table>