Laravel-excel: Comment: enregistrer des fichiers csv/xls en utilisant uniquement ajax

Créé le 14 juil. 2016  ·  12Commentaires  ·  Source: Maatwebsite/Laravel-Excel

Salut les gars,

J'ai vu que certains d'entre nous essayaient de servir un fichier à partir d'une requête ajax. Après quelques recherches, je n'ai pas trouvé de solution claire pour le faire. En peaufinant certains d'entre eux, j'ai exporté avec succès des données csv et xls à partir d'une requête Ajax. Le fait est que la manipulation est différente si le type de fichier est xls, à cause de l'encodage, il y a donc un peu de réglages.

Les données proviennent d'une requête Eloquent typique, convertie en Array :

PHP

if(!empty(Input::get('exportType'))) { //i use a custom get parameter here
            $dd = Excel::create('testFileName', function($excel) use ($data) {
                $excel->sheet('testSheetName', function($sheet) use ($data) {
                    $sheet->fromArray($data->get()->toArray());
                });
                $excel->setTitle($filename);
                $excel->setLastModifiedBy(Carbon::now()->toDayDateTimeString()); //updated has Carbon::now() only now throw exception on vendor/phpoffice/phpexcel/Classes/PHPExcel/Writer/Excel5.php l847 strlen()
            });

            //tweak for serving XLS file from ajax (or go trough download() Excel method for csv files)
            if(Input::get('exportType') == 'xls') {
                $dd = $dd->string();
                $response =  array(
                    'filename' => 'testFileName', //as we serve a custom response, HTTP header for filename is not setted by Excel. From the JS, you need to retrieve this value if type is XLS to set filename
                    'file' => "data:application/vnd.ms-excel;base64,".base64_encode($dd)
                );
                return response()->success($response); //do a json encode
            } else {
                //direct use of Excel download method for non-xls files - xls files need special JS treatment
                $dd->download(Input::get('exportType')); //not XLS, so CSV (didnt tried xlsx, pdf is blank but not sure it's related to this)
            }
            die; //prevent malformed binary data stream, not sure if needed
        }

JS

$.ajax({
      cache: false,
      url: url, //GET route 
      responseType: 'ArrayBuffer', //not sure if needed
      data:  exportParam, //exportType parameter here
      success: function (data, textStatus, request) {

//you could need to decode json here, my app do it automaticly, use a try catch cause csv are not jsoned

        //already json decoded? custom return from controller so format is xls
        if(jQuery.isPlainObject(data)) {
          data = data.data; //because my return data have a 'data' parameter with the content
        }

        //V1 - http://stackoverflow.com/questions/35378081/laravel-excel-using-with-ajax-is-not-working-properly
        //+V3 - http://stackoverflow.com/questions/27701981/phpexcel-download-using-ajax-call
        var filename = "";
        var disposition = request.getResponseHeader('Content-Disposition');
        if (disposition && disposition.indexOf('attachment') !== -1) {
          var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
          var matches = filenameRegex.exec(disposition);
          if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
        }
        if(!jQuery.isPlainObject(data)) { //is CSV - we use blob
           var type = request.getResponseHeader('Content-Type');
           var blob = new Blob([data], { type: type ,endings:'native'});
           var URL = window.URL || window.webkitURL;
           var downloadUrl = URL.createObjectURL(blob);
        }
        var a = document.createElement("a");
        a.href = jQuery.isPlainObject(data) ? data.file : downloadUrl; 
        a.download = jQuery.isPlainObject(data) ? data.filename : filename;
        document.body.appendChild(a);
        a.click();
        a.remove();
      },
      error: function (ajaxContext) {
        toastr.error('Export error: '+ajaxContext.responseText);
      }
    });

ps : ce n'est pas un problème

Commentaire le plus utile

J'avais besoin de retourner un xlsx d'ajax, alors j'ai encore un peu modifié et voici ce que j'obtiens :

PHP
$data est une requête Eloquent convertie en Array.

$myFile= Excel::create("filename", function($excel) use($data) {
   $excel->setTitle('title');
   $excel->sheet('sheet 1', function($sheet) use($data) {
     $sheet->fromArray($data, null, 'A1', true, true);
   });
});

$myFile = $myFile->string('xlsx'); //change xlsx for the format you want, default is xls
$response =  array(
   'name' => "filename", //no extention needed
   'file' => "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,".base64_encode($myFile) //mime type of used format
);
return response()->json($response);

js

$.ajax({
      cache: false,
      url: url, //GET route 
      data:  params, //your parameters data here
      success: function (response, textStatus, request) {
        var a = document.createElement("a");
        a.href = response.file; 
        a.download = response.name;
        document.body.appendChild(a);
        a.click();
        a.remove();
      },
      error: function (ajaxContext) {
        toastr.error('Export error: '+ajaxContext.responseText);
      }
    });

Tous les 12 commentaires

Merci beaucoup cela fonctionne bien pour CSV mais pas xls,

J'avais besoin de retourner un xlsx d'ajax, alors j'ai encore un peu modifié et voici ce que j'obtiens :

PHP
$data est une requête Eloquent convertie en Array.

$myFile= Excel::create("filename", function($excel) use($data) {
   $excel->setTitle('title');
   $excel->sheet('sheet 1', function($sheet) use($data) {
     $sheet->fromArray($data, null, 'A1', true, true);
   });
});

$myFile = $myFile->string('xlsx'); //change xlsx for the format you want, default is xls
$response =  array(
   'name' => "filename", //no extention needed
   'file' => "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,".base64_encode($myFile) //mime type of used format
);
return response()->json($response);

js

$.ajax({
      cache: false,
      url: url, //GET route 
      data:  params, //your parameters data here
      success: function (response, textStatus, request) {
        var a = document.createElement("a");
        a.href = response.file; 
        a.download = response.name;
        document.body.appendChild(a);
        a.click();
        a.remove();
      },
      error: function (ajaxContext) {
        toastr.error('Export error: '+ajaxContext.responseText);
      }
    });

Merci!!

Je reçois l'erreur "Classe 'Excel' introuvable". Pourriez-vous m'aider s'il vous plaît ?

@randomhoodie une source sur la façon dont vous avez trouvé cette solution ?

@eldyvoon comme je l'ai dit, "j'ai modifié" la réponse d'origine, enlevez ce dont je n'avais pas besoin, rendez-le compact et duckduckgo (moteur de recherche) pour le type mime de l'extension ms office xlsx, je n'étais pas sûr que ce soit va fonctionner jusqu'à ce que je l'aie essayé, mais je l'ai essayé avant de poster, et comme cela a fonctionné, je l'ai posté, au cas où quelqu'un le trouverait utile.

J'ai trouvé qu'aucun javascript ni ajax n'est nécessaire. J'ai une page Web avec des liens pour télécharger un tas de fichiers csv/xls/xlsx différents et je ne veux pas du tout que la page soit actualisée. Tout ce que j'ai fait, c'est de connecter un lien à une action qui a renvoyé ce qui suit ...

fonction publique getSpreadsheet() {
$items = Item::all();
Excel::create('items', function($excel) use($items) {
$excel->sheet('ExportFile', function($sheet) use($items) {
$sheet->fromArray($items);
});
})->export('xls');
}

Merveilleux!!!!

Merci @randomhoodie !

Pour le package 3.x, je mettrais à jour votre PHP avec quelque chose comme ceci, selon le guide de mise à niveau :

        $myFile = Excel::raw(new YOUR_Export_Class, \Maatwebsite\Excel\Excel::XLSX);

        $response =  array(
           'name' => "filename", //no extention needed
           'file' => "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,".base64_encode($myFile) //mime type of used format
        );

        return response()->json($response);

Merci @kynetiv , j'utilise la version 3.x, mais j'avais besoin de mettre une extension comme : filename.xlsx

Si vous rencontrez toujours ce problème en 2020. Notez que la version 3.x de Laravel excel a changé alors voici la solution

  1. Envoyez vos données via Ajax à votre contrôleur qui interagit avec l'objet Excel Laravel
  2. Laissez l'objet Excel Laravel envoyer vos données à une vue lame
  3. Stocker la vue de la lame sur le serveur
  4. utilisez js pour télécharger le fichier sur le serveur.
    L'idée est donc d'exporter une vue de lame au format Excel et de la stocker sur un emplacement de disque où vous pouvez la télécharger avec
    javascript.

Exemple:

 $exports = new ReportsExporter($data, $columns);
  Excel::store($exports , 'filename.xlsx', 'custom_disk_location');

définissez votre emplacement de disque personnalisé dans le système de fichiers de configuration comme celui-ci

'custom_disk_location' => [
            'driver' => 'local',
            'root' => public_path('files'),
        ],
...

cela garantira que le fichier excel n'est pas enregistré dans le stockage/l'application
mais l'enregistrera dans le chemin public/files sur votre serveur

retour à votre javascript, téléchargez le fichier comme ceci

function download(filename, path) {
        let element = document.createElement('a');
        element.setAttribute('href', path);
        element.setAttribute('download', filename);

        element.style.display = 'none';
        document.body.appendChild(element);

        element.click();

        document.body.removeChild(element);
    }

appelez la fonction de téléchargement en passant le nom de fichier et le chemin
download("filename.xlsx", location.origin+"files/filename.xlsx");

après le téléchargement n'oubliez pas de revenir sur le serveur et de supprimer celui stocké sur le serveur comme ceci
unlink("fichiers/nom_fichier.xlsx");

J'espère que cela aidera tous ceux qui ont du mal à télécharger laravel-excel via ajax ou javascript.
C'est une meilleure option car elle vous donne plus de flexibilité pour personnaliser votre expérience utilisateur et
donnez-leur des commentaires sur l'état du téléchargement et nommez votre fichier comme vous le souhaitez.

J'avais besoin de retourner un xlsx d'ajax, alors j'ai encore un peu modifié et voici ce que j'obtiens :

PHP
$data est une requête Eloquent convertie en Array.

$myFile= Excel::create("filename", function($excel) use($data) {
   $excel->setTitle('title');
   $excel->sheet('sheet 1', function($sheet) use($data) {
     $sheet->fromArray($data, null, 'A1', true, true);
   });
});

$myFile = $myFile->string('xlsx'); //change xlsx for the format you want, default is xls
$response =  array(
   'name' => "filename", //no extention needed
   'file' => "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,".base64_encode($myFile) //mime type of used format
);
return response()->json($response);

js

$.ajax({
      cache: false,
      url: url, //GET route 
      data:  params, //your parameters data here
      success: function (response, textStatus, request) {
        var a = document.createElement("a");
        a.href = response.file; 
        a.download = response.name;
        document.body.appendChild(a);
        a.click();
        a.remove();
      },
      error: function (ajaxContext) {
        toastr.error('Export error: '+ajaxContext.responseText);
      }
    });

J'avais besoin de retourner un xlsx d'ajax, alors j'ai encore un peu modifié et voici ce que j'obtiens :

PHP
$data est une requête Eloquent convertie en Array.

$myFile= Excel::create("filename", function($excel) use($data) {
   $excel->setTitle('title');
   $excel->sheet('sheet 1', function($sheet) use($data) {
     $sheet->fromArray($data, null, 'A1', true, true);
   });
});

$myFile = $myFile->string('xlsx'); //change xlsx for the format you want, default is xls
$response =  array(
   'name' => "filename", //no extention needed
   'file' => "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,".base64_encode($myFile) //mime type of used format
);
return response()->json($response);

js

$.ajax({
      cache: false,
      url: url, //GET route 
      data:  params, //your parameters data here
      success: function (response, textStatus, request) {
        var a = document.createElement("a");
        a.href = response.file; 
        a.download = response.name;
        document.body.appendChild(a);
        a.click();
        a.remove();
      },
      error: function (ajaxContext) {
        toastr.error('Export error: '+ajaxContext.responseText);
      }
    });

si bon

Cette page vous a été utile?
0 / 5 - 0 notes