Run script BEFORE exporting begins - Buttons Plugin

Run script BEFORE exporting begins - Buttons Plugin

VisualiseVisualise Posts: 4Questions: 1Answers: 0
edited February 2016 in Free community support

Hi there,

I need to trigger a function which makes some changes to the DataTable at the point that a user hits one of the export buttons (e.g. print, csv etc). These changes need to take place before the export/action actually commences, but it doesn't look like there are any events being fired here.

Looking at the documentation I can see that there is the 'button-action' event (https://datatables.net/reference/event/button-action), but this only fires after the export has started, so my changes are not carried through into the export.

Is there anything I can do to achieve running some code before the export actually starts? I guess having a 'before' event fire will be a feature request otherwise...

Thanks,
Elan

Answers

  • VisualiseVisualise Posts: 4Questions: 1Answers: 0
    edited February 2016

    So if anyone else is ever wondering how to do this, I figured it out!

    I ended up extending the button and overriding it's 'action' method, adding in my own code and then calling the original action method so it carries on with it's normal functionality afterwards. See below for an example.

    $('#example').DataTable({
        "buttons": [
            {
                extend: 'print',
                action: function(e, dt, button, config) {
                    
                    // Add code to make changes to table here
    
                    // Call the original action function afterwards to
                    // continue the action.
                    // Otherwise you're just overriding it completely.
                    $.fn.dataTable.ext.buttons.print.action(e, dt, button, config);
                }
            }
        ]
    });
    

    Note: If you want to do this with other buttons that have both HTML5 and Flash versions then you can check for HTML5 support to determine which corresponding action to call. E.g.

    ...
    {
        extend: 'csv',
        action: function(e, dt, button, config) {
            
            // Add code to make changes to table here
    
            // Call the original action function afterwards to
            // continue the action.
            // Otherwise you're just overriding it completely.
            if ($.fn.dataTable.ext.buttons.csvHtml5.available( dt, config )) {
                $.fn.dataTable.ext.buttons.csvHtml5.action(e, dt, button, config);
            }
            else {
                $.fn.dataTable.ext.buttons.csvFlash.action(e, dt, button, config);
            }
        }
    },
    ...
    

    Hope this helps anyone else out there who might have run into the same or similar problem!

    Elan

  • joshjjejoshjje Posts: 1Questions: 0Answers: 0

    Thanks for coming back and posting the solution Elan, this was exactly what I was looking for.

  • lordterrinlordterrin Posts: 22Questions: 10Answers: 1
    edited February 2017

    This is awesome. Thank you for this!

    I found that my code was still not executing "properly" as the exporting of really large data sets was causing the front-end to freeze up, so I added in a timeout prior to the function running:

    'buttons'         : [
            { extend  : 'csv', 
              text    : '<img class="format_3_excel_export_button" src="../../img/excel_small.png" title="Export this entire table to Excel">',  
              title   : 'CSV Export',
              action  : function(e, dt, button, config) {
                toastr.info("Wait a moment while your download generates...");
                setTimeout(function(){
                  $.fn.dataTable.ext.buttons.csvHtml5.action(e, dt, button, config);
                }, 1000);
              } 
            }
          ],    
    
  • androclusandroclus Posts: 2Questions: 0Answers: 0
    edited May 2017

    I agree with joshjje and lordterrin: Thanks, Elan. This definitely got me in the ballpark.

    In my case, for some reason, it was still not quite working, and in my Firefox Web Developer Console (with Javascript and Logging turned on), I was getting this message:

    TypeError: this.processing is not a function [Learn More]

    I found the solution (per this discussion) was that I needed to call it in the following way instead, because of some kind of scoping issue:

    $.fn.dataTable.ext.buttons.csvHtml5.action.call(this, e, dt, button, config);

    (I don't know, maybe that is because i am using DT v 1.10 (latest as of today), and something has changed in the newer version(s)? Just a guess.)

    Anyway, I hope that helps someone out there.

    IMHO, this example -- adding functionality to a button action() and then calling the class's pure action() method again, to continue on with normal functioning -- should be one of those given in the docs on the Buttons example page.

  • allanallan Posts: 61,650Questions: 1Answers: 10,094 Site admin

    Its a change in Buttons. v1.3 introduced the new processing function for the buttons to show that they are busy doing something. But to be able to access it they need to use this, which is why the scope is required.

    Allan

  • allanallan Posts: 61,650Questions: 1Answers: 10,094 Site admin

    IMHO, this example -- adding functionality to a button action() and then calling the class's pure action() method again, to continue on with normal functioning -- should be one of those given in the docs on the Buttons example page.

    Good point! It will be done :)

    Allan

  • allanallan Posts: 61,650Questions: 1Answers: 10,094 Site admin

    Finally committed here. I'll deploy it to the site soon.

    Allan

  • raj_craj_c Posts: 3Questions: 1Answers: 0

    @Visualise , this helped. But how do I actually apply the changes made to the actual payload that will be exported?

    I have a datatable with a list of transactions. The status of each transaction (completed or not) is in the last column of the table. Now I want to export only the completed transactions into my Excel/CSV.

    I've done the filtering of the data array, fetched by this.data(), based on transaction status, inside the action callback, but how do I assign the filtered array back to the actual data that will be considered for exporting?

    Is this the right way to do it, or is there something else that I missed?

    Thanks
    Raj

  • raj_craj_c Posts: 3Questions: 1Answers: 0

    Hey, about my question above, I was able to figure it out. You'll need to place the filtering logic in customizeData instead of action, and you're all set. :)

    Thanks
    Raj

  • jmogollonjmogollon Posts: 1Questions: 0Answers: 0

    In case that somebody run into the "TypeError: Cannot read property 'processing' of undefined" calling a base action from a button:

    Instead of this use dt.button(button)

    Example:
    action: function (e, dt, button, config) { $.fn.dataTable.ext.buttons.excelHtml5.action.call(dt.button(button), e, dt, button, config); }

  • soseki_msoseki_m Posts: 7Questions: 1Answers: 0
    edited April 2019

    Hi,

    I am trying to show the message to the user like following inside action.

    action: function ( e, dt, node, config ){
      $('#loading').show();
      $.fn.dataTable.ext.buttons.excelHtml5.action.call(this, e, dt, node, config);     
      $('#loading').hide();
    }
    

    <div id="downloading-excel" style="display:none;"><img src="/assets/img/loading.gif"></div>
    However, it seems this dose not work at all.

    Do you have any suggestion for this?

    Best regards,

    soseki

  • colincolin Posts: 15,142Questions: 1Answers: 2,586

    Hi @soseki_m ,

    Did you mean

    $('#loading').show();
    

    and not

    $('#downloading-excel').show();
    

    If no joy, we're happy to take a look, but as per the forum rules, please link to a test case - a test case that replicates the issue will ensure you'll get a quick and accurate response. Information on how to create a test case (if you aren't able to link to the page you are working on) is available here.

    Cheers,

    Colin

  • soseki_msoseki_m Posts: 7Questions: 1Answers: 0
    edited April 2019

    Hi @colin

    The HTML was wrong.

    That should be following.

    <div id="loading" style="display:none;"><img src="/assets/img/loading.gif"></div>
    

    I was modifying the source code what was wrong with it so.

    Then, when I put alert() to the source code like following I can see 2 alerts popped up.

    action: function ( e, dt, node, config ){
      alert('Hey');
      $.fn.dataTable.ext.buttons.excelHtml5.action.call(this, e, dt, node, config);    
      alert('Yes');
    }
    

    On the other hands, jQuery is not working at all.

    When I put $('#loading').show(); to debug console in the chrome, it is working okay.

    I will make a test case when I have time for this.
    Just for now, alert() is working okay and so I am using it.

    Regards,
    soseki

  • PL47ERPL47ER Posts: 5Questions: 1Answers: 0
    edited May 2019

    @soseki_m

    The $('#loading').show(); and $('#loading').hide(); might be working as well if alert() is working. What I have noticed is, after firing the first alert() message, the second alert() is also fired straight away. The function for dataTable is still called after 1 sec in the background. So my understanding was the jQuery show and hide events are performed but you may not notice any output on screen because as soon as show event fired, hide event fired after that and so element is hidden again.

    I use UIkit on my project and I have tested on my project using UIkit Modals.

    Here is my code and its working fine. I had to add hide event in the buttons.html5.js file though.

    Code while initializing the buttons in my project script.

    action: function ( e, dt, node, config ){
        UIkit.modal('#loading').show();
        setTimeout(function(){
            $.fn.dataTable.ext.buttons.copyHtml5.action.call(dt.button(this), e, dt, node, config);
        }, 1000);
    }
    

    Code in buttons.html5.js file on line 863

    Original
        this.processing( false );
        return;
    Edit
        this.processing( false );
        **UIkit.modal('#loading').hide();
        return;**
    

    Also what did not work for me was

    $.fn.dataTable.ext.buttons.copyHtml5.action.call(dt.button(button), e, dt, node, config); OR $.fn.dataTable.ext.buttons.copyHtml5.action.call(this, e, dt, node, config);

This discussion has been closed.