Reputation: 47
I'm trying to download the excel from flask using Ajax call. it's showing the response code as 200 but excel is not downloading and the error messages are as follows.
Ajax Request :
$("#genExcel").on("click", function() { var xhttp = new XMLHttpRequest();
// Data to post
var dataarray = {};
// Use XMLHttpRequest instead of Jquery $ajax
xhttp.onreadystatechange = function() {
var a;
if (xhttp.readyState === 4 && xhttp.status === 200) {
// Trick for making downloadable link
a = document.createElement('a');
const objectURL = window.URL.createObjectURL(xhttp.response);
a.href = objectURL
//const objectURL = URL.createObjectURL(object)
// Give filename you wish to download
a.download = "test-file.xlsx";
a.style.display = 'none';
document.body.appendChild(a);
a.click();
}
};
// Post data to URL which handles post request
xhttp.open("POST", '/genexcel');
xhttp.setRequestHeader("Content-Type", "application/json");
// You should set responseType as blob for binary responses
//xhttp.responseType = 'blob';
xhttp.send(JSON.stringify(dataarray));
});
Flask function :
@app.route('/genexcel', methods=["GET", "POST"])
def createExcel():
if request.method == 'POST':
data = request.json
# process json data
return send_file(strIO, attachment_filename='test.xlsx', as_attachment=True)
Errors :
at XMLHttpRequest.xhttp.onreadystatechange
Upvotes: 0
Views: 2116
Reputation: 128
Hopefully I've understood you correctly. Here is a very simple example using the data Array you provided. You could modify to suit your needs:
Flask Functions
from flask import Flask, render_template, request, url_for, send_file
import xlsxwriter
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/genexcel', methods=["GET", "POST"])
def createExcel():
if request.method == 'POST':
data = request.get_json(force=True)
# process json data
createExcel(data['data'])
file_path = 'static/files/test.xlsx'
return send_file(file_path, attachment_filename='test.xlsx', as_attachment=True)
def createExcel(data):
workbook = xlsxwriter.Workbook('static/files/test.xlsx')
worksheet = workbook.add_worksheet()
row_no = 0
col_no = 0
for row in data:
col_no = 0
for entry in row:
worksheet.write(row_no, col_no, entry)
col_no += 1
row_no += 1
workbook.close()
app.run(debug=True, port=5010)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Test</title>
</head>
<body>
Testing
<button id="genExcel">Direct Download</button>
<button id="genExcelFlask">Flask Download</button>
</body>
<script>
var btn = document.getElementById("genExcel");
var btnFlask = document.getElementById("genExcelFlask");
var dataArray = {
data: [
[1, "A", 100],
[2, "B", 200],
],
};
btn.addEventListener("click", (e) => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((resp) => resp.blob())
.then((blob) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.style.display = "none";
a.href = url;
// the filename you want
a.download = "todo-1.json";
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
alert("your file has downloaded!"); // or you know, something with better UX...
})
.catch(() => alert("oh no!"));
});
btnFlask.addEventListener("click", (e) => {
console.log(JSON.stringify(dataArray));
fetch("{{ url_for('createExcel') }}", {
method: "post",
body: JSON.stringify(dataArray),
})
.then((resp) => resp.blob())
.then((blob) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.style.display = "none";
a.href = url;
// the filename you want
a.download = "test.xlsx";
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
alert("your file has downloaded!"); // or you know, something with better UX...
})
.catch(() => alert("oh no!"));
});
</script>
</html>
Upvotes: 1
Reputation: 128
Here is an example using the fetch API. The first button just does a straight JS download. The second button uses the Flask route to do the download. Hope it helps.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Test</title>
</head>
<body>
Testing
<button id="genExcel">Direct Download</button>
<button id="genExcelFlask">Flask Download</button>
</body>
<script>
var btn = document.getElementById("genExcel");
var btnFlask = document.getElementById("genExcelFlask");
btn.addEventListener("click", (e) => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((resp) => resp.blob())
.then((blob) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.style.display = "none";
a.href = url;
// the filename you want
a.download = "todo-1.json";
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
alert("your file has downloaded!"); // or you know, something with better UX...
})
.catch(() => alert("oh no!"));
});
btnFlask.addEventListener("click", (e) => {
fetch("{{ url_for('createExcel') }}")
.then((resp) => resp.blob())
.then((blob) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.style.display = "none";
a.href = url;
// the filename you want
a.download = "test.xlsx";
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
alert("your file has downloaded!"); // or you know, something with better UX...
})
.catch(() => alert("oh no!"));
});
</script>
</html>
Flask Function
from flask import Flask, render_template, request, url_for, send_file
@app.route('/genexcel', methods=["GET", "POST"])
def createExcel():
if request.method == 'POST':
data = request.json
print(data)
# process json data
file_path = 'static/files/test.xlsx'
return send_file(file_path, attachment_filename='test.xlsx', as_attachment=True)
Upvotes: 0