Download Excel file generated in component?

I am generating an Excel file to download from the Livewire component and how to make it downloadable?

      public function export()
      {
             $filename = 'export.xlsx';
             // here is generated a "normal" file download response of Laravel
             return Excel::download(new CustomExcelExport(), $filename);
      }

This kind of downloadable response Livewire is just ignoring… I do not really want to save a temporary files and make a redirect. Just I do not see any mentioning about “download”. Any ideas or undocumented finding? :slight_smile:

Just any binary download option from component would be fine for me…

I would consider using a regular Laravel Single Action Controller for this case.

It’s just not working. I made a redirect to a controller from Livewire component and download works. But only once, after download Livewire component stops responding. It has to be a url to the route…
Very sad.

By using a regular Laravel Controller I mean skip the Livewire part altogether.
From your blade view you would add a link to that Controller and generate the xlsx from there.

<a href="{{ route('export') }}">Export</a>

You don’t need to generate the xlsx inside a Livewire method.
I think for this particular case it would be much simpler using “raw” Laravel.

Right it is much “simpler”, because there is no other way. And you have to pass to the route all settings selected in the Livewire component, and you have to create a new route and a new controller and parse and validate settings again.
But in the end I had to make it like you suggested…

I’m actually saying it’s simpler, but without knowing the whole context of your scenario maybe you are right trying to keep things in Livewire where you have all pieces together.
One thing you could do to minimize this is to create a “ExportService” class to extract the logic that is in your Livewire method and call this service in the Controller to keep it slim, or, even call this service directly from the route definition.

Whatever I do, it has to be a link to create download via controller (using service or other packages) and this link need to have sufficient information to create a report with all settings defined in Livewire component.

How about using Livewire to generate only the URL based on it’s properties?
I’m guessing you have some inputs where the user select the options and click “Download”, right?
Let the user configure the report and when it is ready, expose a URL, or a form with a Download button that post to that route/controller.
I think the user wouldn’t even have to leave the page because the browser just present the download confirmation over the screen.

I’m having the same issue with Livewire 2

The file download is as suggested in the docs (tried all methods) but after the download (which works), the component throws a javascript error whenever I try to interact with the component.

Uncaught (in promise) TypeError: Cannot read property '$wire' of undefined
    at Livewire.value (index.js:29)
    at eval (eval at saferEval (alpine.js:115), <anonymous>:3:78)
    at saferEval (alpine.js:115)
    at new Component (alpine.js:1411)
    at alpine.js:1556
    at alpine.js:1538
    at walk (alpine.js:87)
    at walk (alpine.js:91)
    at Component.walkAndSkipNestedComponents (alpine.js:1532)
    at Component.initializeElements (alpine.js:1549)

Any suggestions anyone?

Take a look at this thread it may help you

Just to be clear, my component works perfectly with component actions to filter the datatable. Its the action of returning a download instead of a view that breaks the component. Once download has been performed the client scripts fail.

I have implemented a workaround for now.

Export the Excel to a file in a temp folder.
Emit a livewire event for ‘downloadready’ and pass the filepath with the event

Create a component and include it in the page.
Have the component listen for ‘downloadready’ events
grab the path and perform the download.

This process seems to stop the main component from breaking.

component:

<?php

namespace App\Http\Livewire;

use Illuminate\Support\Facades\Storage;
use Livewire\Component;

class DownloadReady extends Component
{

    public $listeners=['downloadready'];

    public function downloadready($file)
    {
        return Storage::download($file);
    }

    public function render()
    {
        return view('livewire.download-counts');
    }
}

view:

<div></div>
4 Likes