0

In my application (Yii) I have a Ajax Submit Button which triggers the generation of an Excel file (using PHPExcel). On success I use a hidden form to submit the file to get it downloaded :

<div class="reporting">
    <?php
        $this->beginWidget('zii.widgets.jui.CJuiDialog',array(
            'id'=>'mydialog',
            'options'=>array(
                'title'=>'Warning!',
                'autoOpen'=>false, //true,
                'modal'=>'true',
                'width'=>'auto',
                'height'=>'auto',
                'open' => 'js:function(event, ui) {
                }',
                'close' => 'js:function(event, ui) {
                    $(".ui-dialog:has(#mydialog)").empty().remove();
                }',
            )
        )); 
    ?>
    <table class="contentheader">
        <tr>
            <td>
                <?php echo CHtml::DropDownList('dropDownId', $lastyear, $yearslist, array('options'=>array($lastyear=>array('selected'=>true)) )); ?>
            </td>
        </tr>
    </table>
    <br />
    <?php echo CHtml::ajaxSubmitButton('Form Ajax Submit Button',
        CHtml::normalizeUrl(array('/planning/xlsAbsences')), 
            array(
                'type'=>'POST',
                'beforeSend' => "function(request) { console.log('beforeSend'); }",
                'data'=>'js:$("#select-year-form").serialize()+"&year="+$("#dropDownId :selected").text()',
                'success' => function(response, status, request){
                    $("#mydialog").dialog("close"); 
                    var disp = request.getResponseHeader("Content-Disposition");
                    if (disp && disp.search("attachment") != -1) {
                        var filename = disp.substring(disp.indexOf("filename=") + 10, disp.length-1);
                        var form = $("<form method=\"POST\" action=\"index.php?r=planning/dl\">");
                        form.append($("<input type=\"hidden\" name=\"content\" value=\"" + request.responseText + "\">"));
                        form.append($("<input type=\"hidden\" name=\"filename\" value=\"" + filename + "\">"));
                        $("body").append(form);
                        form.submit();
                    }
                }
                'complete' => "function(request) { console.log(request); }",
                'error' => "function(data) { alert('erro'+data); }",
            ),
            array('name' => 'run', 'class' => 'btn btn-success')
    ); ?>
    <?php $this->endWidget('zii.widgets.jui.CJuiDialog');
        echo CHtml::link(Yii::t('app','app.menu.reporting.planning.xlsabsence'), '#', array( 
            'onclick'=>'$("#mydialog").dialog("open"); return false;',
        ));
    ?>
</div>

Problem is that the generated file is not a valid Excel file. I suppose that the content of the Excelfile is in request.responseText. I have seen that the generated file that can't be opened by Excel, is encoded in UTF (without BOM). If I generate the file without Ajax Submit Button the file is ok. But its seems to be encoded in ANSI. I was using Notpad++ to see encoding information. When I convert UTF (without BOM) to ANSI the result is not better.

What am I missing here ?

EDIT : I don't know if my description is not clear enough - the Excel file does not exist. The Excel file content is generated when submitting Ajax Submit Button in a CJuiDialog - for example the user opens dialog and chosses a parameter - this generates an Excel File depending on the parameter selected by the user. As the file does not exist I can't see how to download it. The only solution I found to go through a hidden form.

EDIT2 : I published the whole view code (above)

G. Trennert
  • 561
  • 3
  • 12
  • 23
  • Are you actually submitting the retrieved Excel back to the server to force it to download? That seems like a huge overhead. Just return the download URL (which sets content-disposition header and such) from the Ajax call and do a JavaScript redirect to this URL. – Koen. Mar 02 '14 at 11:22
  • I edited my post to make things more clear - are you sure that this can be done more easyly ? – G. Trennert Mar 02 '14 at 14:52

2 Answers2

0

Here you go, this is what you are trying to achive: http://jqueryfiledownload.apphb.com/

See more about it here: Download a file by jQuery.Ajax

Community
  • 1
  • 1
Mihai P.
  • 9,307
  • 3
  • 38
  • 49
  • I edited my post to make things more clear - I suppose that to use this plugin the file has to exist - this is not my case ... – G. Trennert Mar 02 '14 at 14:53
  • You are generating the file on the server already, you are just not saving it, but that does not mean that it does not exist. It does exist because you generate it. Of course you can use the plugin because it does exactly what you want. – Mihai P. Mar 02 '14 at 22:26
0

There is no need to do this using a ajax call.

If you submit data to a URL which returns content with the Content-Disposition header set, the browser won't open the page, but will prompt for download.

So lets say this is what you have now:

$.ajax({
    type: 'POST',
    url: '/excel/generate.php',
    'success' => function(response, status, request){
        $("#mydialog").dialog("close"); 
        var disp = request.getResponseHeader("Content-Disposition");
        if (disp && disp.search("attachment") != -1) {
            var filename = disp.substring(disp.indexOf("filename=") + 10, disp.length-1);
            var form = $("<form method=\"POST\" action=\"index.php?r=planning/dl\">");
            form.append($("<input type=\"hidden\" name=\"content\" value=\"" + request.responseText + "\">"));
            form.append($("<input type=\"hidden\" name=\"filename\" value=\"" + filename + "\">"));
            $("body").append(form);
            form.submit();
        }
    }
});

You can replace that for

var form = $('<form/>', {method: 'POST', action: '/excel/generate.php'});
form.appendTo('body');
form.submit();
Koen.
  • 25,449
  • 7
  • 83
  • 78
  • I suppose that if I try this I can't close the dialog automatically :( – G. Trennert Mar 02 '14 at 15:48
  • Just close the dialog before the `form.submit();` – Koen. Mar 02 '14 at 16:38
  • I don't get it excatly : as I said I'm coding in PHP (Yii) and your code is javascript - I edited my post to give the complete view action code - So can you telle what I have to replace by what exactly ? – G. Trennert Mar 03 '14 at 21:41
  • Generating the Excel file happens server side, so only posting to the server (with javascript) and returning the Excel file with download headers should be enough. – Koen. Mar 06 '14 at 08:03