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.
Is there any jQuery.getJSON() equivalent in MooTools? I have a json file named data.json and I want to get its content by calling data.json file using MooTool. Is it possible? I tried Request.JSON() method but it didn't work for me. The below is my code,
var json_req = new Request.JSON({
url:'../public_html/data/data.json',
method: 'get',
secure: true,
data:{
json: true
},
onSuccess: function (res){
this.result = res;
},
onFailure: function(){
this.result = "failed";
}
}).send();
Also from the http://demos111.mootools.net/ I found an Ajax class named Ajax() which they are widely using through out their tutorial. But in MooTools documentation I didn't find this Ajax() class. I tried to use the Ajax() by replacing my Request.JSON(), but got an "Ajax not defined" error. What is this Ajax class and how can we use it in MooTools?
Here is a simple example of the functionality you are looking after. Basically wrapping a function around the Class... you could use the Class directly also.
function getJSON(url, callback) {
new Request.JSON({
url: url,
onSuccess: callback
}).send();
}
// and invoque it:
getJSON('/echo/json/', function(json) {
console.log(json);
});
you can check it live here: https://jsfiddle.net/w64vo2vm/
This one works for me
window.addEvent('domready', function() {
new Request.JSON({
url: url,
data: {'delay': 1},
method: 'post',
onSuccess: function(response) {
var myJSON = JSON.encode(response)
console.log(myJSON);
}
}).send();
})
You may see the result here
http://jsfiddle.net/chetabahana/qbx9b5pm/
I have a small function for this task. Here's the code
var configJson;
function klak_readJson(fileurl) {
var myRequest = new Request({
url: fileurl,
method: 'get',
onRequest: function(){
console.log('loading '+fileurl+'...');
},
onSuccess: function(responseText) {
console.log('received bytes '+responseText.length);
configJson=JSON.parse(myRequest.response.text);
}
});
myRequest.send();
}
Call the function to store the JSON object into configJson
klak_readJson('/js/test.json');
Hope it helps.
I'm facing an issue with ajax that several users here also encountered but the proposed solution do not seem to work for my case.
in my index.php file, I have:
<pre>
<script>
function ButtonManager()
{
$( "button" ).click(function()
{
var context = $(this).attr('type');
var page_type = $(this).attr('page');
var referrer = $(this).attr('referrer');
var form_type = $(this).attr('form');
var object_id = $(this).attr('object');
var postData = 'page_type='+page_type+'&form_type='+form_type+'&referrer='+referrer+'&id='+object_id;
$( '#indicator' ).css( "display", "block" );
if (context == 'post_form')
{
var formData = $('#submit_content').serialize();
postData = postData+'&context=post_form&'+formData;
}
if ((context == 'load_form') || (context == 'filter_form'))
{
postData = postData +'&context=load_form';
if (context == 'filter_form')
{
var filter1 = $('select[name=filter1]').val();
var filter2 = $('select[name=filter2]').val();
var filter3 = $('select[name=filter3]').val();
postData = postData + '&filter1='+filter1+'&filter2='+filter2+'&filter3='+filter3;
}
}
$.ajax
({
type: 'POST',
url: 'php/sl.php',
data: postData,
cache: false,
async: false,
dataType: 'html',
success: function(result)
{
ManageLayer(form_type+'_content');
$('#'+form_type+'_content').html(result);
$( '#indicator' ).css( "display", "none" );
},
error: function(XMLHttpRequest, textStatus, errorThrown)
{
alert(XMLHttpRequest.status);
alert(XMLHttpRequest.responseText);
$( '#indicator' ).css( "display", "none" );
},
});
});
}
</script>
<button type="load_form" page="home" referrer="navigation" form="edit" object="">test</button>
</pre>
when a click on the test button, the script calls sl.php to retrieve some html with other buttons in it.
in the output I get from the server I have added:
<pre>
<script>
var myvar=ButtonManager();
</script>
<button type="post_form" page="home" referrer="navigation" form="edit" object="">test2</button>
</pre>
The goal of the ButtonManager function is to manage all my buttons in one function so it needs to be available/known everywhere (in index.php where it's loaded and in all the output I can get from sl.php).
I have added the var myvar=ButtonManager() line because it's the only way I have found to make sure the function is known by the server output. The drawback is that the function is executed multiple times instead of one even if I don't click on the test2 button.
So I'm looking either for a way to prevent my function from being executed multiple times or an alternative to make the function available everywhere.
I don't know what approach would be the best, I'm a casual developper programming for fun and javascript / ajax is not the language I know the best.
Thanks
Laurent
I got the answer from another forum but I wanted to share it in case others are having the same problem.
Code to be used should be like this:
<pre>
$( document ).on("click", "button", function() {
</pre>
It makes the function available to objects that do not exist yet.
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')
Ajax.ActionLink("Link name",....)
it is possible to put checkbox in place of "Link name" ?
if so how?
thanks,
Yes, of course that it is possible. You could use a standard checkbox:
#Html.CheckBoxFor(
x => x.Foo,
new {
data_url = Url.Action("SomeAction", "SomeController"),
id = "mycheckbox"
}
)
and then in your separate javascript file use jQuery to subscribe to the change event of this checkbox and unobtrusively AJAXify it:
$(function() {
$('#mycheckbox').change(function() {
var data = {};
data[$(this).attr('name')] = $(this).is(':checked');
$.ajax({
url: $(this).data('url'),
type: 'POST',
data: data,
success: function(result) {
// TODO: do something with the result
}
});
});
});