responsive-resize event will be infinitely triggered

responsive-resize event will be infinitely triggered

jmeilejmeile Posts: 28Questions: 4Answers: 0

Right now, I'm working on a responsive Datatable, where I want to hide a column while showing the table on a desktop and on a landscape table. The row should be shown only on mobiles and portrait tablets.

Here is a small test case:
https://jsfiddle.net/jmeile/n4pkdau8/30/

If you debug the Fiddle using the Developer Tool from Mozilla or Chrome and put a break-point inside the responsive-resize handler (line 34 in the js iFrame), then you will see that that event will be infinitely triggered.

To try it, just open this link:
https://jsfiddle.net/jmeile/n4pkdau8/30/show

Press: Run, open the iframe in a new tab, press F12 and put the break-point.

I saw that this behavior will stop if I comment the lines: 24 and 27 from the jsFiddle. Basically this two:
data_table.columns( [3] ).visible( true );
data_table.columns( [3] ).visible( false );

So, this two lines trigger the event again and that's why it will be kept running infinitely.

I really need those two lines since the idea is to hide the age column while on a desktop or a landscape tablet and show it on the other devices.

I tried this things without any success:
* Stop event propagation with: e.stopPropagation();. This is the current implementation
* Adding a global variable, but it seems that inside the event handler that global variable can't be read. It says always: undefined

From this Stackoverflow answer:https://stackoverflow.com/a/1922012, I tried everything:
* Appending a boolean flag to the e.data -> It keeps running
* Disabling the event handler with .off(), then re-enabling with: .on(). It will run only once, so, it won't be re-enabled.
* Adding and removing a css class -> It keeps running

So, basically what I need is to temporary disable the responsive-resize event. Any idea on how to achieve this? Is there perhaps a better way of achieving what I want?

Best regards
Josef

Answers

  • kthorngrenkthorngren Posts: 20,139Questions: 26Answers: 4,734

    Maybe try invoking the event handler from inside the show_hide_column function and use jQuery one() instead of .on(), something like this:

        function show_hide_column(data_table) {
          if (data_table.responsive.hasHidden()) {
            //Some columns are hidden, so, show the controls
            data_table.columns( [3] ).visible( true );
          } else {
            //No columns are hidden, so, hide the controls
            data_table.columns( [3] ).visible( false );
          }
          data_table.draw();
        my_table.one( 'responsive-resize',
                         function ( e, datatable, columns ) {
          e.stopPropagation();
          show_hide_column(datatable);
        } );
        }
    } );
    

    Maybe you can use Responsive class logic to achieve what you want.

    Kevin

  • allanallan Posts: 61,431Questions: 1Answers: 10,048 Site admin

    Hi Josef,

    I'm working on a responsive Datatable, where I want to hide a column while showing the table on a desktop and on a landscape table. The row should be shown only on mobiles and portrait tablets.

    The easiest way to do that is to use the mobile and tablet-p classes on that column.

    However, that isn't what your code is currently doing - rather you are attempting to show a column if any others are hidden.

    For that, we could hijack the dtr-control class: https://jsfiddle.net/CloudTables/4bj9avcn/ . You might need to disable the show / hide click event handler, but is that more inline with what you are looking for?

    The responsive-resize event is a bit tricky because it is async - we have a small debounce in so it doesn't just trigger rapidly, but it makes this sort of thing a little more complex!

    Allan

  • jmeilejmeile Posts: 28Questions: 4Answers: 0
    edited November 2021

    @kthorngren Regarding your answer: as far as I know the .one() handler will be executed only one; however, I need to show/hide the column each time that the user enters or leaves the responsive view, which on my case it would be the mobile and tablet-p modes; the other modes will show the full table.

    Regarding the class logic, I already tried to set the age column to "mobile" and "table-p", but that's not the result I want. See the next screenshots and you will see why I don't want that.

    @allan I tried with the dr-controll class and assigned it to the "age" column, which is the one I actually want to hide or show according to the view, but it is not working as I want, see: https://jsfiddle.net/jmeile/kezo36n0/5

    On desktop and tablet-l modes it is doing what I want: hide the age column. However, on mobile and tablet-p modes, I want that column to be shown as a detail and not as a column. This is what your suggestion does:

    But this is what I really want:

    My original code is working; however, that handler will be triggered infinitely and I think it slows the rendering of my table and sometime the pagination won't work.

    I guess, I will try this with the $(window).resize event instead. I will have to see the window dimensions. I don't like this solution because I will have to hard code the breakpoint dimensions, but as I see it seems to be the only one that seems to work

  • jmeilejmeile Posts: 28Questions: 4Answers: 0

    MMM, my comments got blocked again :'(

    I guess your system doesn't like when I edit my answer several times. Anyway, just for the records: I will try now the $(window).resize event. I don't like it since I will have to hard code the viewport dimensions, but it seems that it is the only thing that will work.

  • jmeilejmeile Posts: 28Questions: 4Answers: 0

    Ok, I solved the problem with $(window).resize. The best thing is that I don't have to hard code the dimensions of the viewports. I only used the function: responsive.hasHidden(), which is really what I want to check. Here the final version:

    https://jsfiddle.net/jmeile/n4pkdau8/74

    I don't know if this is the best approach, but at least the event handler won't be infinitely triggered.

  • colincolin Posts: 15,112Questions: 1Answers: 2,583

    Nice, thanks for reporting back,

    Colin

  • jmeilejmeile Posts: 28Questions: 4Answers: 0
    edited November 2021

    There is only one thing that I would like to know. On lines 22 and 23, I'm doing this:

    var data_table = $('#example');
    var data_table_instance = data_table.DataTable();
    

    This is inside a function called: show_hide_column. I tried to work with a global variable, but it tells me that that variable isn't defined. Is there any better way of solving this? I'm really concern about line 23: would that line recreate the DataTable each time or will just call the one that is already on memory?

  • colincolin Posts: 15,112Questions: 1Answers: 2,583
    edited November 2021

    That's because the my_table variable wouldn't be defined until the table initialises, but your show_hide_column() function is called in initComplete, before that initialisation completes. What you've done is fine, as the DataTable has been initialised, calling DataTable() without any options just returns the existing table. You could do a global variable like this perhaps, but it's only a couple of lines shorter,

    Colin

  • kthorngrenkthorngren Posts: 20,139Questions: 26Answers: 4,734
    edited November 2021

    The code in your example looks like this:

    $(document).ready(function() {
        var my_table = $('#example').DataTable( {
          responsive: {
            details: {
              display: $.fn.dataTable.Responsive.display.childRowImmediate
            }
          },
          columns: [
              null,
              null,
              null,
              { "visible": false },
              null,
              null
          ],
          initComplete: function () {
            show_hide_column();
          }
        } );
           
        function show_hide_column() {
          var data_table = $('#example');
          var data_table_instance = data_table.DataTable();
          if (data_table_instance.responsive.hasHidden()) {
            //Some columns are hidden, so, show the controls
            data_table_instance.columns( [3] ).visible( true );
          } else {
            //No columns are hidden, so, hide the controls
            data_table_instance.columns( [3] ).visible( false );
          }
        }
        
        /* Part of this code was gotten from:
         * - Datatables on-the-fly resizing
         *   https://stackoverflow.com/a/12391296
         */
        $(window).resize(function() {
          clearTimeout(window.refresh_size);
          window.refresh_size = setTimeout(function() { show_hide_column(); }, 250);
        });
    
    } );
    

    The variable my_table should be within scope and available in your show_hide_column function. The two lines (22-23) you are asking about can be combined into one and since you have the Datatable initialized they are just getting an instance to the Datatable API as described here.

    Kevin

  • jmeilejmeile Posts: 28Questions: 4Answers: 0
    edited November 2021

    @colin Thanks for your example, it works. One more question: how do you get the jquery object from the DataTable instance?

    @kthorngren This is not entirely truth. I already tried with my_table, but it will fire this exception:

    Uncaught TypeError: my_table is undefined
        show_hide_column https://fiddle.jshell.net/jmeile/n4pkdau8/78/show/light/:539
        initComplete https://fiddle.jshell.net/jmeile/n4pkdau8/78/show/light/:534
        e https://cdn.datatables.net/v/dt/dt-1.11.3/r-2.2.9/datatables.min.js:102
        map jQuery
        F https://cdn.datatables.net/v/dt/dt-1.11.3/r-2.2.9/datatables.min.js:102
        Pa https://cdn.datatables.net/v/dt/dt-1.11.3/r-2.2.9/datatables.min.js:75
        Ba https://cdn.datatables.net/v/dt/dt-1.11.3/r-2.2.9/datatables.min.js:74
        f https://cdn.datatables.net/v/dt/dt-1.11.3/r-2.2.9/datatables.min.js:119
        u https://cdn.datatables.net/v/dt/dt-1.11.3/r-2.2.9/datatables.min.js:120
        jQuery 2
        u https://cdn.datatables.net/v/dt/dt-1.11.3/r-2.2.9/datatables.min.js:110
        DataTable https://cdn.datatables.net/v/dt/dt-1.11.3/r-2.2.9/datatables.min.js:199
        <anonymous> https://fiddle.jshell.net/jmeile/n4pkdau8/78/show/light/:519
        jQuery 11
    light:539:11
    

    So, it doesn't work when it first gets called in initComplete. Colin already explain why this happened:

    that's because the my_table variable wouldn't be defined until the table initialises, but your show_hide_column() function is called in initComplete, before that initialisation completes.

    You may try it on my last test case and see it by yourself:
    https://jsfiddle.net/jmeile/n4pkdau8/79/

    Best regards
    Josef

  • kthorngrenkthorngren Posts: 20,139Questions: 26Answers: 4,734

    So, it doesn't work when it first gets called in initComplete. Colin already explain why this happened:

    Yep, I agree with that. Forgot you were calling it from initComplete.

    Kevin

  • jmeilejmeile Posts: 28Questions: 4Answers: 0

    Regarding my last question, I just figured out how to do it:

    var table_id = data_table_instance.table().node().id
    var data_table_jquery = $('#' + table_id);
    

    Yes, I could just do: $('#example'), but I don't want to hard code the id inside the function, so that it works for more DataTables. Another option would be to add the id parameter, but why to do this when everything is already available inside the DataTable object

  • colincolin Posts: 15,112Questions: 1Answers: 2,583

    Yep, I was just about to reply and say table().node() was the way to go.

    Colin

Sign In or Register to comment.