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?
RedirectCommandfrom 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