Call controller in Ajax to download a file in Grails - ajax

I'm new to Grails and I'm having troubles for downloading a document generated in my controller.
My jQuery
$("#exportAllSelectedData").click(function() {
var dataToExport = $("#dataToExport").val();
jQuery.ajax(
{type:'POST',
data:'dataToExport=' + dataToExport ,
dataType: 'json',
url:'/myapp/mycontroller/exportPreferences'});;
});
My Controller
def exportPreferences ()
{
File file = File.createTempFile("export",".xml");
String dataToWrite = params.dataToExport;
file.write(dataToWrite);
response.contentType = "application/octet-stream";
response.setHeader "Content-disposition", "attachment; filename=${file.name}";
response.outputStream << file.bytes;
response.outputStream.flush();
}
I was expecting to download the outputStream with my browser but nothing happened.
What am I doing wrong ?
Edit :
Thanks Rahul.
It worked fine with:
$("#exportAllSelectedData").click(function() {
var dataToExport = $("#dataToExport").val();
window.location="<g:createLink controller="mycontroller"
action="exportPreferences"/>"+"?dataToExport="+dataToExport
});

You do not required the Ajax to download a file.
You can simply use window.location to download your file.
Example:
$("#exportAllSelectedData").click(function() {
window.location="<g:createLink controller="mycontroller" action="exportPreferences" />"
});
If you try with Ajax, you will get(render) file text
Example:
$("#exportAllSelectedData").click(function() {
$.ajax({
type: "GET",
url: "<g:createLink controller="demo" action="exportPreferences" />",
success: function (data) {
console.log(data);
}
});
});
Hope this will helps you.

Related

Unable to generate pdf in laravel controller

I had write some sample codes to generate pdf in my laravel controller. It get a 200 response code but the pdf is not generating.
Below is my code.
function exportPDF() {
// instantiate and use the dompdf class
$dompdf = new PDF();
$dompdf->loadHtml('<h1>hello world</h1>');
// (Optional) Setup the paper size and orientation
$dompdf->setPaper('A4', 'landscape');
// Render the HTML as PDF
$dompdf->render();
// Output the generated PDF to Browser
return $dompdf->stream();
}
But this is working when i directly include the code inside route in web.php file.
Route::get('/generate-pdf', function () {
$pdf = App::make('dompdf.wrapper');
$pdf->loadHTML('<h1>Test</h1>');
return $pdf->stream();
});
EDITED
web.php
Route::post('/report-audit-export-pdf', 'ReportAuditController#exportPDF');
.js
window.exportPDF = function() {
var hidden_category = $('#hidden_category').val();
$.ajax({
type: "POST",
url: '/report-audit-export-pdf',
data: {
},
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
error: function(jqXHR, textStatus, errorThrown) {
console.log("jqXHR : " + jqXHR + " and textStatus : " + textStatus + " and errorThrown : " + errorThrown);
},
success: function(content) {
// alert("Success");
}
});
}
May i know what the problem is?
You cannot generate PDFs via Ajax because Ajax requests expect a response, which Laravel sends back as JSON by default. So what you could do, is make a normal GET route that will display the PDF e.g:
Route::get('display-pdf', 'ReportAuditController#exportPDF');
Since your ajax does not POST any data (your data object is empty), you could bypass your ajax request and simply use an anchor
Display PDF
If for some reason, you still want to use Ajax, you can use the success response from the ajax request like this
$.ajax({
type: "POST",
url: '/data-url',
data: {},
success: function(content) {
window.location.href = '/display-pdf';
}
});

call server-side REST function from client-side

In the case, on the server side have some archive restApi.js with REST functions. My REST functions works fine, i test with Prompt Command.
In my client side have some archive index.ejs, And I want to call with this file.
My restApi.js: Server-side
var Client = require('./lib/node-rest-client').Client;
var client = new Client();
var dataLogin = {
data: { "userName":"xxxxx","password":"xxxxxxxxxx","platform":"xxxx" },
headers: { "Content-Type": "application/json" }
};
var numberOrigin = 350;
client.registerMethod("postMethod", "xxxxxxxxxxxxxxxxxx/services/login", "POST");
client.methods.postMethod(dataLogin, function (data, response) {
// parsed response body as js object
// console.log(data);
// raw response
if(Buffer.isBuffer(data)){
data = data.toString('utf8');
console.log(data);
re = /(sessionID: )([^,}]*)/g;
match = re.exec(data);
var sessionid = match[2]
console.log(sessionid);
openRequest(sessionid, numberOrigin); // execute fine
}
});
function openRequest(sessionid, numberOrigin){
numberOrigin+=1;
var dataRequest = {
data: {"sessionID":sessionid,"synchronize":false,"sourceRequest":{"numberOrigin":numberOrigin,"type":"R","description":"Test - DHC","userID":"xxxxxxxxxx","contact":{"name":"Sayuri Mizuguchi","phoneNumber":"xxxxxxxxxx","email":"xxxxxxxxxxxxxxxxxx","department":"IT Bimodal"},"contractID":"1","service":{"code":"504","name":"Deve","category":{"name":"Developers"}}} },
headers: { "Content-Type": "application/json" }
};
client.post("xxxxxxxxxxxxxxxxxxxxxxxxx/services/request/create", dataRequest, function (data, response) {
// parsed response body as js object
// console.log(data);
// raw response
console.log(data);
});
}
My index.ejs: Client side
<html>
<head> ------------- some codes
</head>
<meta ------- />
<body>
<script>
function send() {
$.ajax({
type: "POST",
url: "restApi.js",
data: '{ sendData: "ok" }',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (result) {
alert("successful!" + result.d);
}
});
}
</script>
<script src="restApi.js"></script>
</body>
</html>
I've try see others examples but does not work (Ajax).
And I need to know how to solved this, if have other Best practice for it, please let me knows.
In my console (Chrome) show if I call the ajax function:
SyntaxError: Unexpected token s in JSON at position 2 at JSON.parse (<anonymous>) at parse (C:\xxxxxxxxxxxxxxxxxxxxxxxxx\node_modules\body-parser\lib\types\json.js:88:17) at C:\xxxxxxxxxxxxxxxxxxxxxxxxx\node_modules\body-parser\lib\read.js:116:18
And if I click (BAD Request) show:
Obs.: Same error than app.js, but app.js works fine.
Cannot GET /restApi.js
In the case the file restApi.js Is a folder behind the index.
Folder:
Obs.: public folder have the index.ejs
Your problem is bad url. In case if you have fiule structure like this you have to point as shown in image
Based on the error I think the data you are posting via AJAX is not in correct syntax.
Change function send() as following.
function send() {
var obj = { "sendData" : "ok" };
$.ajax({
type: "POST",
url: "restApi.js",
data: obj,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (result) {
alert("successful!" + result.d);
}
});
}
This should resolve the error you are facing.
Try this now...
function send() {
var obj = {
sendData : "ok"
};
$.ajax({
type: "POST",
url: "Your url",
data: obj,
dataType: "json",
success: function (result) {
alert("successful!" + result.d);
},
error: function (error) {
console.log("error is", error); // let us know what error you wil get.
},
});
}
Your url is not pointing to js/restapi js.
and what code do you have in js/restapi js?
if your action page is app js you have to put it in url.
url:'js/restapi.js',

How to change url dropzone? URL dynamically with ajax success

I read this: https://github.com/enyo/dropzone/wiki/Set-URL-dynamically but i dont got success... :(
I have 1 form...
And i send the inputs with ajax.
The ajax returns the new id of user. in this moment i want to change de url dropzone for to set path to id of the new user.
$.ajax({
type: "POST",
url: "class/inserir.php?funcao=teste",
data: formdata,
dataType: "json",
success: function(json){
if(json.sucesso=="sim"){
alert("Wait! Sending Pictures.");
this.options.url = "class/upload_img.php?"+json.id;
myDropzone.processQueue();
}else{
location.href="home.php?ir=cad_animal&cad=nao&erro="+json.erro;
}
}
});
var myDropzone = new Dropzone("#imagens", {
url: "class/upload_imgteste.php",
paramName: "file", // The name that will be used to transfer the file
maxFilesize: 1, // MB
addRemoveLinks : true,
dictResponseError: "Não foi possível enviar o arquivo!",
autoProcessQueue: false,
thumbnailWidth: 138,
thumbnailHeight: 120,
});
sorry for my bad english!
Thanks for all.
You may add a function on dropzone's "processing" event listener.
Dropzone.options.myDropzone = {
init: function() {
this.on("processing", function(file) {
this.options.url = "/some-other-url";
});
}
};
Here is the link where I got the code and it works for me: https://github.com/enyo/dropzone/wiki/Set-URL-dynamically
change this
this.options.url = "class/upload_img.php?"+json.id;
to this
myDropzone.options.url = "class/upload_img.php?"+json.id;
Does that work?
New answer for an old question only because I found this answer and the link to the dropzone wiki and didn't like it. Modifying the options of the plugin multiple times like that seems very wrong.
When dropzone uses some options it runs it through a resolveOption function passing in a files array. In the current branch you can define a function for the options: method, url and timeout.
Here's a complete working example including delaying for the ajax:
Dropzone.autoDiscover = false;
const doStuffAsync = (file, done) => {
fetch('https://httpbin.org/get').then((response) => {
file.dynamicUploadUrl = `https://This-URL-will-be-different-for-every-file${Math.random()}`
done();//call the dropzone done
})
}
const getMeSomeUrl = (files) => {
return `${files[0].dynamicUploadUrl}?sugar&spice`;
}
let myDropzone = new Dropzone("#my-awesome-dropzone", {
method: "put",
accept: doStuffAsync,
url: getMeSomeUrl
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.4.0/min/dropzone.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.4.0/min/dropzone.min.css">
<form action="/file-upload" class="dropzone" id="my-awesome-dropzone">
</form>
If you need to change the URL dropzone posts to dynamically for each file, you can use the processingfile event and change the options.url.
<form id="my-dropzone" action="/some-url" class="dropzone"></form>
<script>
Dropzone.options.myDropzone = {
init: function() {
this.on("processing", function(file) {
this.options.url = "/some-other-url";
});
}
};
</script>
Another way that worked for me (accept event callback):
$('div#dropzone').dropzone({
options...,
accept: function (file, done) {
this.options.url = 'the url you want';
}
});
BlueWater86's answer didn't work for me. But I agree that changing myDropzone.options.url each time is bad practice, and it actually doesn't work if you are dragging a lot of files into the uploader at the same time.
I wrote the following code and it works well for uploading one file at time and for many at a time. I'm using Backblaze B2 but it should also work for S3.
myDropzone.on('addedfile', function(file) {
options = {
filename: file.name,
type: file.type,
_: Date.now()
};
// Make the request for the presigned Backblaze B2 information, then attach it
$.ajax({
url: '/presign_b2',
data: options,
type: 'GET',
success: function(response){
file.dynamicUrl = response['url'];
myDropzone.enqueueFile(file);
}
});
});
myDropzone.on('sending', function(file, xhr) {
xhr.open("PUT", file.dynamicUrl); // update the URL of the request here
var _send = xhr.send;
xhr.send = function() {
_send.call(xhr, file);
}
});

ajax post to jsp receive null string

I am fetching data from a form using jquery and posting with ajax to a .jsp file.
when i try to receive the data in jsp scriplet using request.get parameter then i get null.
var values = {}; // Create empty javascript object
$("select").each(function() { // Iterate over selects
values[$(this).attr('name')] = $(this).find(":selected").attr('data-citycode'); // Add each to features object
});
var format = "dd/mm/yyyy";
values["datepicker1"] = $("#datepicker1 div").datepicker("getFormattedDate", format);
values["datepicker2"] = $("#datepicker2 div").datepicker("getFormattedDate", format);
//var url ="list_flights.jsp";
$.ajax({
type: "GET",
url: "list_flights.jsp",
async: false,
data: {
values: JSON.stringify(values)
},
error: function(data) {
console.log(data);
},
success: function(data) {
console.log(data);
window.location = "list_flights.jsp";
}
});
and the jsp scriplet
<% out.print(request.getParameter("values")); %>
output
null
it seems that on success of ajax you are changing the window location
success: function(data) {
console.log(data);
window.location = "list_flights.jsp";
}
which is making another request and do not have the values attribute in request.
success: function(data) {
console.log(data);
window.location = "list_flights.jsp?values=" + JSON.stringify(values);
}
But it doesn't make sense of redirecting on success and calling the ajax to the same jsp. You should call a servlet from ajax which will give you the response and based on that response you should redirect to another page.

Extjs 4 downloading a file through ajax call

The problem is very simple: i have to download a file when i submit a form, it's an ajax call when the form is submitted which lets me build a file with the data taken from the form, server side, and then send it as a link to an alert. The fact is that my boss want the file to be downloaded directly and not through a link in an alert. So i had to make sure that the file is available server side through tornado(web):
self.set_header('Content-Type', 'application/octet-stream')
self.set_header('Content-Disposition', 'attachment; filename=clients_counter.zip')
with open("static/clients_counter.zip", 'r') as f:
while True:
data = f.read()
if not data:
break
self.write(data)
self.finish()
The server side code seems to work fine, but the client side (extjs4.1) is really a nightmare. This is how my ajax call looks like now, and it doesn't work:
Ext.Ajax.request({
method : "GET",
url : 'http://whatever.com/count?client='+client+'&start='+start+'&end='+end,
timeout : 30000,
success :
function (response) {
//Ext.Msg.alert(response.responseText);
desktop.getWindow('count-win').doClose();
return response;
}//handler,
failure :
function(response) {
alert("Wrong request");
}});
After reading on various sources from Ext JS forum and here in stackoverflow, below is the approach I've chosen (using Ext JS version 4.2.1):
downloadFile: function(config){
config = config || {};
var url = config.url,
method = config.method || 'POST',// Either GET or POST. Default is POST.
params = config.params || {};
// Create form panel. It contains a basic form that we need for the file download.
var form = Ext.create('Ext.form.Panel', {
standardSubmit: true,
url: url,
method: method
});
// Call the submit to begin the file download.
form.submit({
target: '_blank', // Avoids leaving the page.
params: params
});
// Clean-up the form after 100 milliseconds.
// Once the submit is called, the browser does not care anymore with the form object.
Ext.defer(function(){
form.close();
}, 100);
}
I had a similar problem trying to download an Excel File in an Ajax call I solved it this way:
Make a standard sumbit instead of Ajax.
var form = Ext.create('Ext.form.Panel', { // this wolud be your form
standardSubmit: true, // this is the important part
url: '../ObtenerArchivoAdjuntoServlet'
});
form.submit({
params: {
nombreArchivo: nombreArchivo
}
});
After this you would be able return the desired file.
After extracting/reading many posts, I managed to get this simple method to work..
Ext.create('Ext.form.Panel', {
renderTo: Ext.getBody(),
standardSubmit: true,
url: 'URL'
}).submit({params: {'PARAM1': param1, 'PARAM2': param2}});
I think you can take a much easier solution. Forget about the ajax, and just get plain old js to open the file for you:
window.open('http://whatever.com/count?client='+client+'&start='+start+'&end='+end)
This will open a new tab and start the download from there.
The following code used to download the file using extjs 5 or 6. Add the following code to method and invoke this for button action. This downloads the file directly insteadof opening in new tab.
use an iframe like this:
/**
* prints the file
*/
printReport: function () {
var url = 'downloadURL';
Ext.Ajax.request({
url: url,
method: 'GET',
autoAbort: false,
success: function(result) {
if(result.status == 204) {
Ext.Msg.alert('Empty Report', 'There is no data');
} else if(result.status == 200) {
Ext.DomHelper.append(Ext.getBody(), {
tag: 'iframe',
frameBorder: 0,
width: 0,
height: 0,
css: 'display:none;visibility:hidden;height:0px;',
src: url
});
}
},
failure: function() {
//failure here will automatically
//log the user out as it should
}
});
}
Copied the answer from extjs forum
Option:2
If you want to open the file in new tab
/**
* open file in tab
*/
openReport: function () {
var url = 'downloadURL';
Ext.Ajax.request({
url: url,
method: 'GET',
autoAbort: false,
success: function(result) {
if(result.status == 204) {
Ext.Msg.alert('Empty Report', 'There is no data');
} else if(result.status == 200) {
var win = window.open('', '_blank');
win.location = url;
win.focus();
}
},
failure: function() {
//failure here will automatically
//log the user out as it should
}
});
}
You cannot use ajax to download file. I've implemented file downloading in extjs which is like ajax. see the blog ajaxlikefiledownload.
FileDownload.downloadFile = function(arguments) {
var url = arguments['url'];
var params = arguments['params'];
var successCallback = arguments['success'];
var failureCallback = arguments['failure'];
var body = Ext.getBody();
var frame = body.createChild({
tag:'iframe',
cls:'x-hidden',
id:'hiddenframe-frame',
name:'iframe'
});
var form = body.createChild({
tag:'form',
cls:'x-hidden',
id:'hiddenform-form',
action: url,
method: 'POST',
target:'iframe'
});
if (params) {
for (var paramName in params) {
form.createChild({
tag:'input',
cls:'x-hidden',
id:'hiddenform-'+paramName,
type: 'text',
text: params[paramName],
target:'iframe',
value: params[paramName],
name: paramName
});
}
}
form.dom.submit();
FileDownload.isFinished(successCallback,failureCallback);
};
FileDownload.isFinished = function(successCallback,failureCallback) {
//Check if file is started downloading
if (Ext.util.Cookies.get('fileDownload') && Ext.util.Cookies.get('fileDownload')=='true' ) {
//Remove cookie call success callback
Ext.util.Cookies.set('fileDownload', null, new Date("January 1, 1970"),application.contextPath+'/');
Ext.util.Cookies.clear('fileDownload',application.contextPath+'/');
successCallback();
return;
}
//Check for error / IF any error happens then frame will load with content
try {
if(Ext.getDom('hiddenframe-frame').contentDocument.body.innerHTML.length>0){
Ext.util.Cookies.set('fileDownload', null, new Date("January 1, 1970"),application.contextPath+'/');
Ext.util.Cookies.clear('fileDownload',application.contextPath+'/');
failureCallback();
//Cleanup
Ext.getDom('hiddenframe-frame').contentDocument.body.innerHTML = "";
return;
}
}
catch (e) {
console.log(e);
}
console.log('polling..');
// If we are here, it is not loaded. Set things up so we check the status again in 100 milliseconds
window.setTimeout('FileDownload.isFinished('+successCallback+','+failureCallback+')', 100);
};
Usage :
FileDownload.downloadFile({
url : url,
params : params,
success : function(){
//Success call back here
},
failure : function(){
//Failure callbak here
}
});
In the http response you need to add a cookie nammed fileDownload = true
I just had to ad to the success function of the ajax request:
window.open('urltothefile.ext')

Resources