How to initiate a file download in Extjs 7.0 Modern framework - extjs

In the Extjs classic framework we use Ext.form.Panel to initiate a file download. In the Modern framework I have been unable to get Ext.form.Panel to do the same. So how can I perform a simple file download (of a potentially large file) in the Modern framework. I would rather not have to change the server side code.
This is the code we use in Classic
params={};
params.doc_path=rec.get('server_path');
params.doc_link_name=rec.get('name');
var form = Ext.create('Ext.form.Panel', {
standardSubmit: true,
renderTo: Ext.getBody(),
url: '/document/download',
method: 'POST',
timeout: 120
});
// Call the submit to begin the file download.
// Note that neither Success nor Failure are ever called
form.submit({
params: params
});
This is the server side code in our ruby server
def download
# A small helper to download the file passed in doc_path
send_file params["doc_path"], type: 'application/octet-stream', disposition: 'attachment', filename: params["doc_link_name"]
end
If we try that in Modern our server does not receive the correct url. (We get a routing error).
File upload using a form in Modern works just the same as Classic, so why doesn't the file download work the same?
Does anyone have some sample code on how to use Ext.exporter.file to download a file from a server? I have read the docs and just got lost. And in any case when I put in a require for Ext.exporter.file I get a 404 not found error, so that is out of the question.

I just need click and forget so no need to track success or failure.
Thanks to Imagine-breaker for his answer in this post I implemented this function:
downloadURI: function(uri, name) {
var link = document.createElement("a");
if(!name)name="";
link.setAttribute('download', name);
link.href = uri;
document.body.appendChild(link);
link.click();
link.remove();
}
and call it like this
lfg.downloadURI('/document/download?doc_path=' + encodeURIComponent(rec.get('server_path')),rec.get('name'));
Server side code remains exactly as is. I might implement this in our Classic version of the app as well - it seems so much simpler.

Related

Downloading an Excel file causes it to corrupt

I have a simple service on Angular 2 and Typescript that requests Excel files to a server and then opens a download file dialogue for the user. However, as it is currently, the file becomes corrupt when downloaded.
When downloaded, it opens fine in OpenOffice and derivates, but throws a "File is Corrupt" error on Microsoft Excel, and asks if the user wants to recover as much as it can.
When Excel is prompted to recover the file, it does so successfully, and the recovered Excel has all rows and data that is expected for the Excel file. Comparing the recovered file against opening the file in OpenOffice and derivates evidence no outstanding differences.
The concrete Excel I am trying to download is generated with Apache POI in a microservice, then passed to the main backend and finally served to the frontend for the user to download. Both the backend and microservice are written in Java, through Spark Framework.
I made some tests on the backends, and concluded the problem is not the report generation nor the data transfer:
Asking the microservice to save the generated Excel in a file within the server and then opening such file (hereby file A) in Excel shows that file A is not corrupted.
Asking the main backend server to save the Excel file that it receives from the microservice in a file within itself and then opening such file in Excel (hereby file B) shows that file B is not corrupted.
Downloading both file A and file B through FileZilla from their respective servers yields completely uncorrupted files.
As such, I believe it is safe to assume the Excel becomes corrupted somewhere between the time the file is received on the frontend and the time the user downloads such file. Additionally, the Catalina logs do not evidence any error that might potentially be happening.
I have read several posts that deal with the issue, including a bug report (https://github.com/angular/angular/issues/14083) that included a workaround via XMLHTTPRequest. However, none of the workarounds detailed were successful in solving my issue.
Attached is the code I am using to both obtain the Excel file from the backend and serve it to the user. I am including both an XMLHTTPRequest and an Angular http call (within comments) since those are the two main ways I have been trying to make this work. Additionally, please do take into account the code has been altered to remove information I do not wish to make public.
download(body) {
let reply = Observable.create(observer => {
let xhr = new XMLHttpRequest();
xhr.open('POST', 'URL', true);
xhr.setRequestHeader('Content-type', 'application/json;charset=UTF-8');
xhr.setRequestHeader('Accept', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
xhr.setRequestHeader('Authorization', 'REDACTED');
xhr.responseType = 'blob';
xhr.onreadystatechange = function () {
if(xhr.readyState === 4) {
if(xhr.status === 200) {
var contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
var blob = new Blob([xhr.response], { type: contentType });
observer.next(blob);
observer.complete();
}
else {
observer.error(xhr.response);
}
}
}
xhr.send(JSON.stringify(body));
});
return reply;
/*let headers = new Headers();
headers.set("Authorization", 'REDACTED');
headers.set("Accept", 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
let requestOptions :RequestOptions = new RequestOptions({headers: headers, responseType: ResponseContentType.Blob});
return this.http.post('URL', body, requestOptions);*/
}
Hereby is the code to prompt the user to download the Excel. It is currently made to work with the XMLHTTPRequest. Please do note that I have also attempted to download without resorting to FileSaver, with no luck.
downloadExcel(data) {
let body = {
/*REDACTED*/
}
this.service.download(body)
.subscribe(data => {
FileSaver.saveAs(data, "Excel.xlsx");
});
}
Hereby are the versions of the tools I am using:
NPM: 5.6.0
NodeJs: 8.11.3
Angular JS: ^6.1.0
Browsers used: Chrome, Firefox, Edge.
Any help on this issue would be appreciated. Any additional information you may need I will be happy to provide.
I think what you want is CSV format which open in Excel, update your sevice as follow:
You should tell Angular you are expecting a response of type blob (Binary Large Object) that is your Excel/Csv file.
Also make sure the URL/API on your server is set to accept content-type='text/csv'.
Here's an example with Angular 2.
#Injectable()
export class YourService {
constructor(private http: Http) {}
download() { //get file from the server
this.http.get("http://localhost/..", {
responseType: ResponseContentType.Blob,
headers: new Headers({'Content-Type', 'text/csv'})
}).subscribe(
response => {
var blob = new Blob([response.blob()], {type: 'text/csv'});
FileSaver.saveAs(blob, 'yourFileName.csv');
},
error => {
console.error('something went wrong');
}
);
}
}
Have you tried uploading/downloading your xls file as base64?
var encodedXLSToUpload = 'data:application/xls;base64,' + btoa(file);
Check this for more details: Creating a Blob from a base64 string in JavaScript

how to transfer the taken image using ngcordova file transfer plugin to my ftp

I am trying to upload image to my FTP.
what i have achived so far is in this plnkr
my cordova file transfer looks like
$scope.upload =function(){
var options = {
fileKey: "file",
fileName: "gopi",
chunkedMode: false,
mimeType: "image/jpeg",
params : {'user_token':'Chandru#123', 'user_email':'wepopusers'} // directory represents remote directory, fileName represents final remote file name
};
console.log(options);
$cordovaFileTransfer.upload('ftp://308.3d8.myftpupload.com/', MyService.getImgPath(), options)
.then(function(result) {
// Success!
console.log(result);
console.log("SUCCESS: " + JSON.stringify(result.response));
alert('ftp success');
}, function(err) {
// Error
console.log(err);
alert('ftp fail');
console.log("ERROR: " + JSON.stringify(err));
}, function (progress) {
// constant progress updates
console.log(progress);
});
};
My response of my error function for cordova file looks like
FileTransferError {code: 2, source: "file:///storage/sdcard0/Android/data/com.ionicframework.camera108827/cache/1462186990291.jpg", target: "ftp://308.3d8.myftpupload.com/", http_status: null, body: null…}body: nullcode: 2exception: nullhttp_status: nullsource: "file:///storage/sdcard0/Android/data/com.ionicframework.camera108827/cache/1462186990291.jpg"target: "ftp://308.3d8.myftpupload.com/"proto: Object
I have button TakePicture which will take the pic and show to the user and also I have a function to upload using cordovafiletransfer $scope.upload .
my ftp host is ftp://308.3d8.myftpupload.com/ username and password is given in my coding in this i have a folder name called gopi where my image should store.
my path of the image taken is in imageURI parameter so i used services to set the path.
steps I’m in confusion
1) I am not able to understand the var options object in cordova file transfer plugin.
2) I am not getting any erro while remote debugging but i am only invoking my error funtion in my cordova file transfer.
How can i update my taken image to FTP using IONIC
UPDATE
Thanks to gandhi's answer https://github.com/xfally/cordova-plugin-ftp some how i managed to connect to ftp without multipart.
but sill facing error in this
$window.cordova.plugin.ftp.upload("/ping", "/gopi/ping", function(percent) {
i don't know what to in the first argument and second.
$window.cordova.plugin.ftp.upload("/default.prop", "/gopi/default.prop", function(percent) {
the above line success fully posted to my ftp but i am not able to post my image which is stored in my ping variable.
https://plnkr.co/edit/ETGmdl4B0d5dlHWdJQ9m?p=info
The answer to your first question is available in the official documentation of file transfer plugin. The excerpt is as follow,
options: Optional parameters (Object). Valid keys:
fileKey: The name of the form element. Defaults to file. (DOMString)
fileName: The file name to use when saving the file on the server. Defaults to image.jpg. (DOMString)
httpMethod: The HTTP method to use - either PUT or POST. Defaults to POST. (DOMString)
mimeType: The mime type of the data to upload. Defaults to image/jpeg. (DOMString)
params: A set of optional key/value pairs to pass in the HTTP request. (Object, key/value - DOMString)
chunkedMode: Whether to upload the data in chunked streaming mode. Defaults to true. (Boolean)
headers: A map of header name/header values. Use an array to specify more than one value. On iOS, FireOS, and Android, if a header named Content-Type is present, multipart form data will NOT be used. (Object)
Check out this link for more info.
For your second question, try getting the error code in the error callback function and try to narrow down the problem.
Update: I guess ftp upload is not possible using file transfer plugin. The plugin definition itself states "The FileTransfer object provides a way to upload files using an HTTP multi-part POST or PUT request, and to download files"
You may have to look at this for ftp client for ftp uploads.

angular $sce trustAsResourceUrl from node

im trying to make a streaming service where i stream the content of a file (in this case a video) into a video element.
for this purpose i have downloaded and installed videogular and is now trying to set it up however im sure how to do it.
According to the documentation on videogular to load a video you would need a syntax like this:
sources: [
{src: $sce.trustAsResourceUrl(myMp4Resource), type: "video/mp4"}
]
Which is fine for when you want to load the content in without streaming.
But say for instance you have a node server running at port 8105 and the file you wish to collect had an id of 1 then the result might look something like this:
sources: [
{src: $sce.trustAsResourceUrl('http://localhost:8105/loadvideo/1'), type: "video/mp4"}
]
However in my attempt to do so it would just tell me that the resource is not an actual resource.
My question is how do you stream to a video content (preferably with videogular) and does anyone know of examples where people have made this possible?
Server side code
Okay so my initial idea (and i know this is a change for the code above) was to create a route that took at path:
router.route('/retrieveFile')
.post(function (request, response) {
var path = '../' + request.body.data;
var file = fs.createReadStream(path);
file.pipe(response);
});
And then piped the output of the file.
Then use this to stream the file
If you have video files on your harddrive and you want to serve them all with their filenames, you should just use Express Static to serve them just like any other resource
You can add a path prefix '/videos' to differentiate them from regular resources.
app.use('/videos', express.static('videos'));
Then a video file ./videos/myvid.mp4 would be available as http://localhost:8000/videos/myvid.mp4
To have a file available as a file, you need to set the appropriate headers before piping
And to load the file you'd put this code in your router, and where you're using post, if you don't have a strong reason I'd just use get or all
You might also wanna be able to end the transmission if client decides to disconnect mid-stream
Alternatively you might want to go with res.download instead of streams, which which case appropriate headers and interruptions are automatically handled.
So the whole code might look like this:
router.route('/path/to/video.mp4')
.all(function(req, res){
res.header('content-disposition', 'filename="video.mp4"')
var stream = fs.createReadStream('./resources/video.mp4');
stream.pipe(res);
require('on-finished')(res, stream.abort.bind(stream));
// or simply
res.download(fs.readSync('/path'))
});
Then you can use http://localhost:8000/path/to/video.mp4 to either directly load the video into your browser, it'll play it if it can or simply offer to download. Or you can use this URL in your videgular
sources: [ {src: $sce.trustAsResourceUrl('http://localhost:8000/path/to/video.mp4'), type: "video/mp4"} ]

Downloaded .pdf files are corrupted when using expressjs

I am working on meanjs application generated using https://github.com/DaftMonk/generator-angular-fullstack. I am trying to generate a .pdf file using phantomjs and download it to the browser.
The issue is that the downloaded .pdf file always shows the blank pages regardless of the number of pages. The original file on server is not corrupt. When I investigated further, found that the downloaded file is always much larger than the original file on the disk. Also this issue happens only with .pdf files. Other file types are working fine.
I've tried several methods like res.redirect('http://localhost:9000/assets/exports/receipt.pdf');, res.download('client\\assets\\exports\\receipt.pdf'),
var fileSystem = require('fs');
var stat = fileSystem.statSync('client\\assets\\exports\\receipt.pdf');
res.writeHead(200, {
'Content-Type': 'application/pdf',
'Content-Length': stat.size
});
var readStream = fileSystem.createReadStream('client\\assets\\exports\\receipt.pdf');
return readStream.pipe(res);
and even I've tried with https://github.com/expressjs/serve-static with no changes in the result.
I am new to nodejs. What is the best way to download a .pdf file to the browser?
Update:
I am running this on a Windows 8.1 64bit Computer
I had corruption when serving static pdfs too. I tried everything suggested above. Then I found this:
https://github.com/intesso/connect-livereload/issues/39
In essence the usually excellent connect-livereload (package ~0.4.0) was corrupting the pdf.
So just get it to ignore pdfs via:
app.use(require('connect-livereload')({ignore: ['.pdf']}));
now this works:
app.use('/pdf', express.static(path.join(config.root, 'content/files')));
...great relief.
Here is a clean way to serve a file from express, and uses an attachment header to make sure the file is downloaded :
var path = require('path');
var mime = require('mime');
app.get('/download', function(req, res){
//Here do whatever you need to get your file
var filename = path.basename(file);
var mimetype = mime.lookup(file);
res.setHeader('Content-disposition', 'attachment; filename=' + filename);
res.setHeader('Content-type', mimetype);
var filestream = fs.createReadStream(file);
filestream.pipe(res);
});
There are a couple of ways to do this:
If the file is a static one like brochure, readme etc, then you can tell express that my folder has static files (and should be available directly) and keep the file there. This is done using static middleware:
app.use(express.static(pathtofile));
Here is the link: http://expressjs.com/starter/static-files.html
Now you can directly open the file using the url from the browser like:
window.open('http://localhost:9000/assets/exports/receipt.pdf');
or
res.redirect('http://localhost:9000/assets/exports/receipt.pdf');
should be working.
Second way is to read the file, the data must be coming as a buffer. Actually, it should be recognised if you send it directly, but you can try converting it to base64 encoding using:
var base64String = buf.toString('base64');
then set the content type :
res.writeHead(200, {
'Content-Type': 'application/pdf',
'Content-Length': stat.size
});
and send the data as response.
I will try to put an example of this.
EDIT: You dont even need to encode it. You may try that still. But I was able to make it work without even encoding it.
Plus you also do not need to set the headers. Express does it for you. Following is the Snippet of API code written to get the pdf in case it is not public/static. You need API to serve the pdf:
router.get('/viz.pdf', function(req, res){
require('fs').readFile('viz.pdf', function(err, data){
res.send(data);
})
});
Lastly, note that the url for getting the pdf has extension pdf to it, this is for browser to recognise that the incoming file is pdf. Otherwise it will save the file without any extension.
Usually if you are using phantom to generate a pdf then the file will be written to disc and you have to supply the path and a callback to the render function.
router.get('/pdf', function(req, res){
// phantom initialization and generation logic
// supposing you have the generation code above
page.render(filePath, function (err) {
var filename = 'myFile.pdf';
res.setHeader('Content-type', "application/pdf");
fs.readFile(filePath, function (err, data) {
// if the file was readed to buffer without errors you can delete it to save space
if (err) throw err;
fs.unlink(filePath);
// send the file contents
res.send(data);
});
});
});
I don't have experience of the frameworks that you have mentioned but I would recommend using a tool like Fiddler to see what is going on. For example you may not need to add a content-length header since you are streaming and your framework does chunked transfer encoding etc.

Is it possible to upload files to S3 from browser in IE8?

Now I have this code in javascript.
var file_object = $('#PHOTO').get(0).files[0];
the_form = new FormData();
the_form.append("AWSAccessKeyId", "TESTING");
the_form.append("acl", "authenticated-read");
the_form.append("policy", policy);
the_form.append("signature", signature);
the_form.append("Content-Type", "image/jpeg");
the_form.append("key", "test.jpg");
the_form.append("file", file_object);
$.ajax({
url: "http://S3BUCKET.s3.amazonaws.com",
type: "POST",
data: the_form,
processData: false,
contentType: false
})
It works sweetly, in Chrome, Firefox, except IE6,7,8,9.
The reason is that file object is not supported until IE10!
https://developer.mozilla.org/en-US/docs/Web/API/File
Is there any work-around solution for browsers before IE10?
PS: Code example would be nice!!
Without Flash many things are definitely a no-go. I believe the lib you reference has some Flash fallbacks, but I'm unclear as to whether they can handle all the issues involved. This is something I'm currently dealing with myself, and here are the issues in brief:
Content-Type header in response. IE (without Flash intermediary) will try to download a JSON content type, no way around this that I know without a proxy middleman to fudge headers.
hostname mapping. If you don't map to origin hostname, IE iframe (which is the non-Flash fallback) will not allow you to read the contents of it from the containing window. Fire and forget may be possible, but consuming the response/detecting errors from s3 may not.
I will update this answer as I uncover more in the coming days. This is a large project so we have some pretty significant requirements and I imagine I'll learn a lot in the next week or so.
This is covered in a lot more detail here (not my company/project/post): http://blog.fineuploader.com/2013/08/16/fine-uploader-s3-upload-directly-to-amazon-s3-from-your-browser/

Resources