This may be a duplicate, but I haven't found a solution yet.
In an app I'm working on, there are two export
buttons that should download an Excel file to the user's computer.
One export button performs a POST form method, routing parameters to an action:
<input type="submit" value="EXPORT" id="exportButton" asp-action="ExportResultsData"
asp-route-ClientID="@listItem.ClientID" asp-route-ProcessingType="@listItem.ProcessingType"
asp-route-ProgressType="@Model.ProgressType" asp-route-FileName="@listItem.FileName" />
When clicked, the values are routed to the controller action and they are used to create and return the file to the browser where it is downloaded. All good.
As I've said, I have another button that needs to download another Excel file. However, this one is different because the view model does not contain all the values needed to route to its controller action. Each time I click the button, I need to call a JavaScript function and get a JSON object which has this structure:
{
"draw": 1,
"columns": [
{
"data": "Column1",
"name": "Column1",
"searchable": true,
"orderable": true,
"search": {
"value": "",
"regex": false
}
},
{
"data": "Column2",
"name": "Column2",
"searchable": true,
"orderable": true,
"search": {
"value": "",
"regex": false
}
},
{
"data": "Column3",
"name": "Column3",
"searchable": true,
"orderable": true,
"search": {
"value": "",
"regex": false
}
},
{
"data": "Column4",
"name": "Column4",
"searchable": true,
"orderable": true,
"search": {
"value": "",
"regex": false
}
}
],
"order": [
{
"column": 0,
"dir": "asc"
}
],
"start": 0,
"length": 15,
"search": {
"value": "",
"regex": false
},
"ClientID": 8,
"FeedbackID": "8",
"ProcessingType": "Import"
}
Each time I get these parameters, some of the values may change, and the number of columns may increase/decrease.
I can reach the controller action, bind the parameters to the model, and generate an Excel file successfully but the file does not download and just returns back to the AJAX success
section:
function ExportFeedbackData(clientID, feedbackID, processingType) {
var jqueryParams = GetJqueryParams();
$.ajax({
url: '/Client/ExportFeedbackData',
type: 'POST',
data: {
DatatablesParameters: jqueryParams,
ClientID: clientID,
FeedbackID: feedbackID,
ProcessingType: processingType,
},
success: function (exportedFile) {
console.log(exportedFile);
//file data just returns here and doesn't download
},
error: function (errormsg) {
console.log(errormsg);
}
});
}
Controller action:
//"DatatablesParameters" refers to parameters sent from a JS plugin called Datatables https://datatables.net/
//https://datatables.net/manual/server-side
public IActionResult ExporFeedbackData(DataTablesParameters DatatablesParameters, int ClientID, int FeedbackID, string ProcessingType)
{
DataTable dt = _processingService.ReturnDataTable(DatatablesParameters, ClientID, FeedbackID, ProcessingType);
using (ExcelPackage package = new ExcelPackage())
{
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(ProcessingType);
worksheet.Cells["A1"].LoadFromDataTable(dt, PrintHeaders: true);
for (var i = 0; i < dt.Columns.Count; i++)
{
worksheet.Cells.AutoFitColumns();
}
return File(package.GetAsByteArray(), XlsxContentType, $"{ProcessingType}.xlsx"); //Excel file returned
}
}
So, what I want is to be able to download the file with AJAX, but I can't figure out how to do it. The file can potentially be large as well. I'm also tempted to somehow eliminate AJAX and dynamically generate an <input>
tag, but each time I'd export the values in the jquery object may be different. I'm also open to other solutions.
I'm mainly worried about cleanliness and reliability. With form submission you just click the button and it's downloaded. But with AJAX it looks to be messier.