I've got a form that builds an array of data. On submission, it updates a table displayed in the browser, using AJAX; that works fine.
I want a second submit button that downloads the same data as a CSV file. I've tried a number of variations, but I can't seem to both send the file response and satisfy the AJAX requirement for a returned array.
The button:
$form['download'] = [
'#type' => 'submit',
'#value' => $this->t('Download data'),
'#weight' => '40',
'#ajax' => [
'callback' => '::downloadCallback',
'event' => 'click',
],
];
...and the response section of the callback:
$file_content = $serializer->serialize($data, 'csv');
$response = new Response($file_content);
$disposition = $response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, 'data.csv');
$response->headers->set('Content-Disposition', $disposition);
$form_state->setResponse($response);
I've also tried using this instead of setResponse:
$response->send();
These all result in an error:
TypeError: Argument 1 passed to Drupal\Core\Render\MainContent\AjaxRenderer::renderResponse() must be of the type array, null given, called in /mnt/www/html/mowebd8dev/docroot/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php on line 89 in /mnt/www/html/mowebd8dev/docroot/core/lib/Drupal/Core/Render/MainContent/AjaxRenderer.php on line 45 #0 /mnt/www/html/mowebd8dev/docroot/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php(89): Drupal\Core\Render\MainContent\AjaxRenderer->renderResponse(NULL, Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\Core\Routing\CurrentRouteMatch))
I've tried also returning a simple render array with some dummy markup, and that prevents the error, but still doesn't result in a file download. Is there a way to accomplish this? Or should I just not be using AJAX for this purpose?
RedirectCommand
from the AJAX callback with the URL for a route you create that takes that hash as a parameter. In the controller, load up the tmp file that matches the hash, serve it, then delete it. Voila