Laravel-excel: Cómo: guardar archivos csv / xls usando solo ajax

Creado en 14 jul. 2016  ·  12Comentarios  ·  Fuente: Maatwebsite/Laravel-Excel

Hola tios,

He visto que algunos de nosotros estamos tratando de servir un archivo desde una solicitud ajax. Después de algunas investigaciones, no encontré ninguna solución clara para hacerlo. Al ajustar algunos de ellos, exporté con éxito datos csv y xls desde una solicitud Ajax. La cuestión es que la manipulación es diferente si el tipo de archivo es xls, debido a la codificación, por lo que hay algunos ajustes.

Los datos provienen de una consulta típica de Eloquent, convertida a 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: esto no es un problema

Comentario más útil

Necesitaba devolver un xlsx de ajax, así que lo modifiqué un poco nuevamente y esto es lo que termino con:

PHP
$ data es una consulta Eloquent convertida a 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);
      }
    });

Todos 12 comentarios

Muchas gracias, funciona bien para CSV pero no xls,

Necesitaba devolver un xlsx de ajax, así que lo modifiqué un poco nuevamente y esto es lo que termino con:

PHP
$ data es una consulta Eloquent convertida a 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);
      }
    });

¡¡Gracias!!

Recibo el error "Clase 'Excel' no encontrada". ¿Podrían ayudarme?

@randomhoodie alguna fuente ¿cómo surgió esa solución?

@eldyvoon, como dije, "modifiqué" la respuesta original, eliminé lo que no necesitaba, lo hice compacto y duckduckgo (motor de búsqueda) para el tipo mime de la extensión ms office xlsx, no estaba seguro de que fuera Funcionará hasta que lo probé, pero lo probé antes de publicarlo, y como funcionó lo publiqué, en caso de que alguien lo encontrara útil.

Descubrí que no se necesita javascript ni ajax en absoluto. Tengo una página web con enlaces para descargar un montón de archivos csv / xls / xlsx diferentes y no quiero que la página se actualice en absoluto. Todo lo que hice fue conectar un enlace a una acción que devolvió lo siguiente ...

función pública getSpreadsheet () {
$ elementos = Elemento :: todos ();
Excel :: create ('elementos', función ($ excel) use ($ elementos) {
$ excel-> hoja ('ExportFile', función ($ hoja) use ($ elementos) {
$ hoja-> fromArray ($ elementos);
});
}) -> exportar ('xls');
}

Maravilloso !!!!

¡Gracias @randomhoodie!

Para el paquete 3.x, actualizaría su PHP con algo como esto, según la guía de actualización :

        $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);

Gracias @kynetiv , uso la versión 3.x, pero necesitaba poner una extensión como: filename.xlsx

Si todavía tiene este problema en 2020, tenga en cuenta que la versión 3.x de Laravel Excel ha cambiado, así que aquí está la solución

  1. Envíe sus datos a través de Ajax a su controlador que interactúa con el objeto Laravel Excel
  2. Deje que el objeto de Excel de Laravel envíe sus datos a una vista de hoja
  3. Almacenar la vista de la hoja en el servidor
  4. use js para descargar el archivo en el servidor.
    Entonces, la idea es exportar una vista de hoja como Excel y almacenarla en una ubicación de disco donde pueda descargarla con
    javascript.

Ejemplo:

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

defina su ubicación de disco personalizada en el sistema de archivos de configuración de esta manera

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

esto asegurará que el archivo de Excel no se guarde en el almacenamiento / aplicación
pero lo guardará en la ruta pública / archivos en su servidor

de vuelta a su javascript, descargue el archivo como este

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);
    }

llamar a la función de descarga pasando el nombre del archivo y la ruta
descargar ("nombre de archivo.xlsx", ubicación.origen + "archivos / nombre de archivo.xlsx");

después de la descarga recuerde volver al servidor y eliminar el almacenado en el servidor de esta manera
desvincular ("archivos / nombrearchivo.xlsx");

Espero que esto ayude a cualquiera que tenga dificultades para descargar laravel-excel a través de ajax o javascript.
Esta es una mejor opción, ya que le brinda más flexibilidad para personalizar su experiencia de usuario y
déles su opinión sobre el estado de la descarga y asigne un nombre a su archivo como desee.

Necesitaba devolver un xlsx de ajax, así que lo modifiqué un poco nuevamente y esto es lo que termino con:

PHP
$ data es una consulta Eloquent convertida a 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);
      }
    });

Necesitaba devolver un xlsx de ajax, así que lo modifiqué un poco nuevamente y esto es lo que termino con:

PHP
$ data es una consulta Eloquent convertida a 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);
      }
    });

tan bueno

¿Fue útil esta página
0 / 5 - 0 calificaciones