0

Im trying to generate a basic csv file with some data. When I use an alert inside the ajax call it will show me the data(so there is data passing), but when I click the button it will not generate an CSV file. Im new to yii2 so im still learning.

UPDATED I have changed the files

//view export/index.php

Pjax::begin();

$form = ActiveForm::begin([
    'action'  => yii\helpers\Url::to(['cms-export/index']),
    'options' => ['data' => ['pjax' => true]],
    'layout'  => 'horizontal',
    'fieldConfig' => [
        'horizontalCssClasses' => [
            'label'   => 'col-sm-2',
            'offset'  => 'col-sm-offset-2',
            'wrapper' => 'col-sm-5',
            'hint'    => 'col-sm-5',
        ],
    ],
]);

    echo $form->field($model, 'language')->dropDownList([//some list]);

    echo $form->field($model, 'filename')->textInput()

    echo Html::submitButton('Submit', ['class' => 'btn btn-primary'])';



ActiveForm::end();

Pjax::end();

//model

public function generateCsv(){

  header('Content-Type: application/csv');
  header('Content-Disposition: attachment; filename="sample.csv"');

    $data = [datacomeshere];

    $fp = fopen('php://output', 'w');
    foreach ( $data as $line ) {
        fputcsv($fp, $line, ';');
    }
    fclose($fp);

}

//controller

public function actionIndex()
{

    $model = new Export();

    if ($model->load(Yii::$app->request->post()) && $model->validate()) {

        // validation works, but method does not work
        \common\models\Export::generateCsv();

    }

    return $this->render('index' , ['model' => $model]);

}

When I click the button it will show me an 500 error in the jquery file

xhr.send( options.hasContent && options.data || null );
user759235
  • 2,147
  • 3
  • 39
  • 77

2 Answers2

4

I would suggest the following approach, removing the whole JS code:

Make the link a real one. It makes sense to have a GET request, since you just getting data with the call.

<div class="modal-button-row">
    <a href="cms-export/download" id="export-trigger" class="btn btn-success pull-left">Export</a>
</div>

Modify the action now (probably in CmsExportController) and use the Yii download capability:

public function actionDownload() {
    $csv = Export::generateCsvSomehow(); // this should return a csv string
    return \Yii::$app->response->sendContentAsFile($csv, 'sample.csv', [
           'mimeType' => 'application/csv', 
           'inline'   => false
    ]);
}

More infos in guide: here.

You also need to remove Pjax, since it will do its own stuff with links and forms via JS! Or you have to configure Pjax, e.g. with $formSelector, which goes beyond the scope of this question.

robsch
  • 9,358
  • 9
  • 63
  • 104
  • Okay, nice but sadly this does nothing here, so am I missing something perhaps? – user759235 May 07 '18 at 13:06
  • @user759235 What happens exatly? – robsch May 07 '18 at 13:08
  • @user759235 Does the action get called? Do you get a status 400? – robsch May 07 '18 at 13:10
  • @user759235 You may have to use `href="/cms-export/download"` if the actions does not get called. Or try `$csv = "asdf,fdsa";`. Did you have removed the JS code? – robsch May 07 '18 at 13:15
  • I have updated my examples, im now using activeform as i need some data to pass. You're example does also not work – user759235 May 07 '18 at 13:59
  • 1
    @user759235 What does not work? Why don't you provide clearer information? Please describe what happens! And don't change your question that way – robsch May 07 '18 at 14:07
  • Well I cant say anything more as it does not do anything, the action works, but the method does not do anything...when i put the method in the view file it will work Update: i see an 500 error in the jquery code – user759235 May 07 '18 at 14:09
  • when I use this ill get the error 'mb_strlen() expects parameter 1 to be string, array given in...' – user759235 May 07 '18 at 14:51
  • @user759235 Because `$csv` doesn't seem to be a string. A string containing the whole content of the file is required. – robsch May 07 '18 at 15:12
  • I see, but this still does not work, both ways will now output plain text in the page, so data is passing but not as an file. – user759235 May 08 '18 at 07:00
  • @user759235 Hm... Can you try another browser? Maybe it's a browser setting? `'inline' => false` should open the browser dialog for saving the download. What happens if you set it to `true`? – robsch May 08 '18 at 07:04
  • true or false it still show the data in the file, I do see an other error yii\base\ErrorException: Object of class yii\web\Response could not be converted to string...this error is even present when i use a string – user759235 May 08 '18 at 07:25
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/170594/discussion-between-robsch-and-user759235). – robsch May 08 '18 at 07:29
  • The issue was that pjax is not needed here, without pjax it will generate a working csv file. Thanks for the help!!! – user759235 May 08 '18 at 08:35
1

One problem is definitely that the regular action call always creates headers, cookies and some content (even an empty string, e.g. if you have forgotten the return statement with $this->render(...)) that gets sent to the browser. I supsect that you get some Headers already sent error. So this has to be suppressed so that your CSV code takes control.

Try the following:

 public function actionIndex() {
    $model = new Export();
    if ($model->load(Yii::$app->request->post()) && $model->validate()) {
        \common\models\Export::generateCsv();
        Yii::$app->response->isSent = true;
    } else {
        return $this->render('index' , ['model' => $model]);
    }
}

Btw: Use method: GET in your form if no data gets changed with that call. This is a HTTP standard. POST is used when something gets added or changed.

However, I would recommend my other approach using Response::sendContentAsFile(). This should work with your ActiveForm as well. As noted in that answer you have to remove or configure Pjax.

robsch
  • 9,358
  • 9
  • 63
  • 104