Click event in column header never fired

Click event in column header never fired

galcottgalcott Posts: 53Questions: 15Answers: 1

I'm having a bizarre problem where I'm using identical code for two tables to retrieve the column index when the column header is clicked to change the sort. I'm doing this so I can display the sort field name in a printout. In one table it works perfectly and in the other the code for the event is never executed, as I've confirmed in the debugger. I'm using code that I found in this discussion:
https://datatables.net/forums/discussion/24593/retreive-column-idx-when-clicking-on-header. Is there something I'm not seeing here that would cause this issue?

First table (works perfectly):

  $('#tblHerbs').on( 'click', 'thead th', function () {
    var i;
    i = dtHerbs.column(this).index();
    switch (i) {
      case 0: HerbSort = 'Herb Code'; break;
      case 1: HerbSort = 'Herb Name'; break;
      case 2: HerbSort = 'Gram Cost '; break;
      case 3: HerbSort = 'Inventory'; break;
      case 4: HerbSort = 'Low Inv.'; break;
      case 5: HerbSort = 'Notes'; break;
    }
  });

Second table (nothing happens on click; this code is never reached):

  $('#tblPatients').on( 'click', 'thead th', function () {
    var i;
    i = dtPatients.column(this).index();
    switch (i) {
      case 0: PatientSort = 'Name'; break;
      case 1: PatientSort = 'Formula'; break;
      case 2: PatientSort = 'Prescription Date'; break;
    }
  });

This question has an accepted answers - jump to answer

Answers

  • kthorngrenkthorngren Posts: 21,301Questions: 26Answers: 4,946

    Your code works for me:
    http://live.datatables.net/miyoqoqi/1/edit

    Was doing some other testing with two tables so I copied your code into my test (made a couple changes to match my config) and it works.

    Kevin

  • galcottgalcott Posts: 53Questions: 15Answers: 1

    Yes, it should work in both cases! But on my page only the first one works. It's completely baffling.

  • kthorngrenkthorngren Posts: 21,301Questions: 26Answers: 4,946

    Can you post a test case showing the issue or a link to your page?

    Your snippets of code aren't enough to help troubleshoot.

    Kevin

  • galcottgalcott Posts: 53Questions: 15Answers: 1

    The page is at http://galcott.com/herbpharmacy.com/test.html. Thanks for checking this out.

  • kthorngrenkthorngren Posts: 21,301Questions: 26Answers: 4,946

    I get the following error when trying to access the page:

    Server Error in Application "GALCOTT.COM"
    Internet Information Services 7.5
    Error Summary
    HTTP Error 404.0 - Not Found
    The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
    Detailed Error Information
    Module  IIS Web Core
    Notification    MapRequestHandler
    Handler SSINC-html
    Error Code  0x80070002
    Requested URL   http://galcott.com:80/herbpharmacy.com/test.html
    Physical Path   D:\InetPub\vhosts\galcott.com\httpdocs\herbpharmacy.com\test.html
    Logon Method    Anonymous
    Logon User  Anonymous
    

    Kevin

  • galcottgalcott Posts: 53Questions: 15Answers: 1

    Sorry, bad link. Leave out the .com after herbpharmacy

  • kthorngrenkthorngren Posts: 21,301Questions: 26Answers: 4,946

    Ok, I figured out your test URL, removed the .com from herbpharmacy.com.

    Looks like you are using jQuery UI tabs. I'm no expert but I suspect the problem is the Patients table does not exist when the click event is initialized. I think you will need to execute the click event init code when you active the Patients tab. Then you may need to execute the Herb click event when clicking back to and activating the Herbs tab.

    Kevin

  • galcottgalcott Posts: 53Questions: 15Answers: 1
    edited June 2017

    No, it has nothing to do with the tabs. If you look at the code that's not working you'll see that it comes after the table is initialized. I did it the same way for the Herbs table, which works perfectly. All of that is done before the tabs are created.

    Executing the click event when the Patients tab is activated wouldn't work. It needs to be executed on the actual click when they're in the Patients table. The whole purpose of it is to display the sort order in the printout produced when they click "Print List" on that tab so it has to show the actual current sort order.

    This isn't even really that important but it's just driving me crazy because it makes no sense.

  • bindridbindrid Posts: 730Questions: 0Answers: 119

    right now, I can't get past alert('#tblPatients').order[0][0].toString();

    alerts cannot be chained

  • galcottgalcott Posts: 53Questions: 15Answers: 1

    Sorry, I was just testing some stuff. That code is gone now.

  • kthorngrenkthorngren Posts: 21,301Questions: 26Answers: 4,946

    Maybe you need to delegate the click event to a parent element. Maybe something like this:

    $('#tabs-3').on( 'click', 'table thead th', function () {
    

    To replace this:

    $('#tblPatients').on( 'click', 'thead th', function () {
    

    Kevin

  • galcottgalcott Posts: 53Questions: 15Answers: 1

    That's certainly not something I ever would have thought of, but I tried it and it never got executed either.

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin
    Answer ✓

    You might have hit a DataTables bug here.

    The second table has scrollY: false. For some reason that is dropping DataTables into a rendering mode that displays the table suitable for scrolling.

    I'm not 100% certain that it is a bug since the documentation for scrollY doesn't say that it can be a boolean false value that is given. However, it probably is a good idea to allow for that case - I'll make that change.

    In the mean time, remove scrollY: false (and scrollX: false) and it should work as expected.

    Allan

  • galcottgalcott Posts: 53Questions: 15Answers: 1

    Thank you so much! That fixed it. But why would rendering it in a way suitable for scrolling have any effect on the column header click event?

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin

    Because the table gets split into three different table elements in order to be able to display the scrolling display correctly. The original table (with the id attribute) is the scrolling table body. The header is a cloned table with the thead moved into it. There is, therefore, no way to click on something that would match the selector used.

    Its a pain that split process - it adds a lot of code to DataTables, but I've not found a better way to handle it yet.

    Allan

  • galcottgalcott Posts: 53Questions: 15Answers: 1

    So just for future reference, that means that in any table with scrolling enabled there's no way to get the current sort column index? Or is there another way to do it?

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin

    Sure - use the API: order() will tell you want the current sort condition is.

    Allan

  • chboccachbocca Posts: 90Questions: 14Answers: 1

    Hmmm. This seems like a bug ...

    The same problem occurs when either the scrollX = true or scrollY = true options are included.

    See issue here ... clicking on header does not trigger index, which is what galcott experienced.

    See working correctly here, commenting out scroll option.

    This is a bit of an issue for me because I was using it to work around the current complex header and colReorder incompatibility.

    c

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin

    The issue is that you are selecting elements using:

    $('#example').on( 'click', 'thead th',
    

    But when scrolling is enabled, the table has to be split into parts (header, body and footer), so the header is no longer inside the #example element. You can use table().header() to get the thead element, regardless of if scrolling is enabled or not.

    Allan

  • chboccachbocca Posts: 90Questions: 14Answers: 1

    OK, good. Thank you.

    So, I can see the thead element via

    table.table().header();

    It's

    [object HTMLTableSectionElement]

    and in this case:

    innerHTML gives:

    <tr role="row"><th class="sorting_asc" tabindex="0" aria-controls="example" rowspan="1" colspan="1" style="width: 158px;" aria-sort="ascending" aria-label="Name: activate to sort column descending">Name</th><th class="sorting" tabindex="0" aria-controls="example" rowspan="1" colspan="1" style="width: 244px;" aria-label="Position: activate to sort column ascending">Position</th><th class="sorting" tabindex="0" aria-controls="example" rowspan="1" colspan="1" style="width: 112px;" aria-label="Office: activate to sort column ascending">Office</th><th class="sorting" tabindex="0" aria-controls="example" rowspan="1" colspan="1" style="width: 47px;" aria-label="Age: activate to sort column ascending">Age</th><th class="sorting" tabindex="0" aria-controls="example" rowspan="1" colspan="1" style="width: 109px;" aria-label="Start date: activate to sort column ascending">Start date</th><th class="sorting" tabindex="0" aria-controls="example" rowspan="1" colspan="1" style="width: 94px;" aria-label="Salary: activate to sort column ascending">Salary</th></tr>

    But how do we get the column index of a particular cell in the header? Which was what started this thread.

    In 2014 you wrote:

    To get the column index when clicking in the header you could use:

    $('#example').on( 'click', 'thead th', function () {
    var index = table.column( this ).index();
    } );

    But that does not work when scrollX or scrollY is enabled. Instead of '#example' what element do we specify for onclick to work for 'thead th'?

    c

  • kthorngrenkthorngren Posts: 21,301Questions: 26Answers: 4,946

    See if this code works for you:

      $($('#example').DataTable().table().header()).on( 'click', 'th', function () {
        var index = table.column( this ).index();
        console.log(index);       
      } );
    

    Kevin

  • chboccachbocca Posts: 90Questions: 14Answers: 1

    Yes! Thank you kthorngren!

    As does this basic jQuery (without the datatable function):

    $("th").on('click', function (index, htmlElement) {         
        var index = $(this).index();            
        var cellValue = $(this).text();             
        alert('index = ' + index + ", " + "cellValue = " + cellValue);                  
    });
    

    See working version with scroll here.

    c

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin

    Worth noting that won't work as expected if you use column visibility, since the visible index won't match the data index. Kevin's approach is the one I would recommend.

    Allan

  • chboccachbocca Posts: 90Questions: 14Answers: 1

    Yes, thank you Allan. I understand. I've updated the working version with Kevin's approach here.

  • chboccachbocca Posts: 90Questions: 14Answers: 1

    One more thing ...

    I find colReorder will work with a special form of complex headers, where there is no colspan ... just say a double row header like <thead><tr></tr><tr></tr><thead>.

    See working version here. The columns move correctly without throwing the errors we see when there is colspan, as seen here. I'm presuming that is because colReorder keys on the bottom row in this example.

    But, can I get the column index on-click for the top row in the header? Using Kevin's approach, the index comes back correctly for the second (bottom) header row, but "undefined" in top row. See again here.

    Trying to create a work-around for the current incompatibility between complex headers and colReorder.

    c

  • chboccachbocca Posts: 90Questions: 14Answers: 1

    I do find this generic code works:

    $("th").on('click', function (index, htmlElement) {
    
        var index = $(this).index();
                
        var cellValue = $(this).text();
                    
        alert('index = ' + index + ", " + "cellValue = " + cellValue);
                        
    });
    

    Working demo here.

    But wanted to do within dt if possible.

    c

  • allanallan Posts: 63,455Questions: 1Answers: 10,465 Site admin

    The code you have on your page appears to work for me, although I'd suggest you simply use the table variable rather than $('#example').DataTable().

    I find colReorder will work with a special form of complex headers, where there is no colspan ...

    If it does, then its fluke. ColReorder is not designed for multiple row headers at the moment I'm afraid. Indeed, the DataTables API as a whole is a bit lacking in its support for multiple headers which is why you'd need a bit of a workaround, similar to what you have done, to make it work, since DataTables isn't really "aware" of the second row in the header.

    Allan

This discussion has been closed.