How to download images from a site with phantomjs - coffeescript

I wanna save some images from a site. At the moment I can get the paths to the images but I have no clue how to get and save the images with phantomJs.
findRotationTeaserImages = ->
paths = page.evaluate ->
jQuery('.rotate img').map(-> return this.src).get()
for path, i in paths
console.log(path);
//save the image

I know this is an old question, but you do this pretty simply by storing the dimensions and location of each image on the in an object, then altering the phantomjs page.clipRect so that the page.render() method renders only the area where the image is. Here is an example, scraping multiple images from http://dribbble.com/ :
var page = require('webpage').create();
page.open('http://dribbble.com/', function() {
page.includeJs('//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js',function() {
var images = page.evaluate(function() {
var images = [];
function getImgDimensions($i) {
return {
top : $i.offset().top,
left : $i.offset().left,
width : $i.width(),
height : $i.height()
}
}
$('.dribbble-img img').each(function() {
var img = getImgDimensions($(this));
images.push(img);
});
return images;
});
images.forEach(function(imageObj, index, array){
page.clipRect = imageObj;
page.render('images/'+index+'.png')
});
phantom.exit();
});
});

There is now another way to do this.
var fs = require("fs");
var imageBase64 = page.evaluate(function(){
var canvas = document.createElement("canvas");
canvas.width =img.width;
canvas.height =img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
return canvas.toDataURL ("image/png").split(",")[1];
})
fs.write("file.png",atob(imageBase64),'wb');

Solve this by starting a child process running a node script that download the images:
phantomJs script:
findRotationTeaserImages = ->
paths = page.evaluate ->
jQuery('.rotate img').map(-> return this.src).get()
args = ('loadRotationTeaser.js ' + paths.join(' ')).split(' ')
child_process.execFile("node", args, null, (err, stdout, stderr) ->
phantom.exit()
)
nodeJs script
http = require('http-get');
args = process.argv.splice(2)
for path, i in args
http.get path, 'public/images/rotationTeaser/img' + i + '.jpeg', (error, result) ->

In case image dimensions are known:
var webPage = require('webpage');
/**
* Download image with known dimension.
* #param src Image source
* #param dest Destination full path
* #param width Image width
* #param height Image height
* #param timeout Operation timeout
* #param cbk Callback (optional)
* #param cbkParam Parameter to pass back to the callback (optional)
*/
function downloadImg(src, dest, width, height, timeout, cbk, cbkParam) {
var page = webPage.create();
page.settings.resourceTimeout = timeout; //resources loading timeout(ms)
page.settings.webSecurityEnabled = false; //Disable web security
page.settings.XSSAuditingEnabled = false; //Disable web security
page.open(src, function(status) {
// missing images sometime receive text from server
var success = status == 'success' && !page.plainText;
if (success) {
page.clipRect = {
top: 0,
left: 0,
width: width,
height: height
};
page.render(dest);
}
cbk && cbk(success, cbkParam);
page.close();
});
};

I've experienced really a lot troubles when using the render method. Luckily I finally come up with two better solution. Here is the code I used in my project. First solution has some trouble to update the cookie, so it cannot work well when fetching captcha image. Both method will cause a new http request. But with a few modifications, the second one can ommit such kind of request.
The first one fetches the cookie from phantomJs and makes a new http request using request. The second one uses base64 to pass the image.
async download(download_url, stream) {
logger.profile(`download(download_url='${download_url}')`);
let orig_url = await this.page.property('url');
download_url = url.resolve(orig_url, download_url);
let cookies = await this.page.property('cookies');
let jar = request.jar();
for (let cookie of cookies) {
if (cookie.name !== undefined) {
cookie.key = cookie.name;
delete cookie.name;
}
if (cookie.httponly !== undefined) {
cookie.httpOnly = cookie.httponly;
delete cookie.httponly;
}
if (cookie.expires !== undefined)
cookie.expires = new Date(cookie.expires);
jar.setCookie(new Cookie(cookie), download_url, {ignoreError: true});
}
let req = request({
url: download_url,
jar: jar,
headers: {
'User-Agent': this.user_agent,
'Referer': orig_url
}
});
await new Promise((resolve, reject) => {
req.pipe(stream)
.on('close', resolve)
.on('error', reject);
});
// Due to this issue https://github.com/ariya/phantomjs/issues/13409, we cannot set cookies back
// to browser. It is said to be redesigned, but till now (Mar 31 2017), no change has been made.
/*await Promise.all([
new Promise((resolve, reject) => {
req.on('response', () => {
jar._jar.store.getAllCookies((err, cookies) => {
if (err) {
reject(err);
return;
}
cookies = cookies.map(x => x.toJSON());
for (let cookie of cookies) {
if (cookie.key !== undefined) {
cookie.name = cookie.key;
delete cookie.key;
}
if (cookie.httpOnly !== undefined) {
cookie.httponly = cookie.httpOnly;
delete cookie.httpOnly;
}
if (cookie.expires instanceof Date) {
cookie.expires = cookie.expires.toGMTString();
cookie.expiry = cookie.expires.toTime();
}
else if (cookie.expires == Infinity)
delete cookie.expires;
delete cookie.lastAccessed;
delete cookie.creation;
delete cookie.hostOnly;
}
this.page.property('cookies', cookies).then(resolve).catch(reject);
});
}).on('error', reject);
}),
new Promise((resolve, reject) => {
req.pipe(fs.createWriteStream(save_path))
.on('close', resolve)
.on('error', reject);
})
]);*/
logger.profile(`download(download_url='${download_url}')`);
}
async download_image(download_url, stream) {
logger.profile(`download_image(download_url='${download_url}')`);
await Promise.all([
new Promise((resolve, reject) => {
this.client.once('donwload image', data => {
if (data.err)
reject(err);
else
stream.write(Buffer.from(data.data, 'base64'), resolve);
});
}),
this.page.evaluate(function (url) {
var img = new Image(), callback = function (err, data) {
callPhantom({
event: 'donwload image',
data: {
err: err && err.message,
data: data
}
});
};
img.onload = function () {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext("2d").drawImage(img, 0, 0);
callback(null, canvas.toDataURL("image/png").replace(/^data:image\/(png|jpg);base64,/, ""));
};
img.onerror = function () {
callback(new Error('Failed to fetch image.'));
};
img.src = url;
}, download_url)
]);
logger.profile(`download_image(download_url='${download_url}')`);
}

Related

Angular 6 Downloading file from rest api

I have my REST API where I put my pdf file, now I want my angular app to download it on click via my web browser but I got HttpErrorResponse
"Unexpected token % in JSON at position 0"
"SyntaxError: Unexpected token % in JSON at position 0↵ at JSON.parse (
this is my endpoint
#GetMapping("/help/pdf2")
public ResponseEntity<InputStreamResource> getPdf2(){
Resource resource = new ClassPathResource("/pdf-sample.pdf");
long r = 0;
InputStream is=null;
try {
is = resource.getInputStream();
r = resource.contentLength();
} catch (IOException e) {
e.printStackTrace();
}
return ResponseEntity.ok().contentLength(r)
.contentType(MediaType.parseMediaType("application/pdf"))
.body(new InputStreamResource(is));
}
this is my service
getPdf() {
this.authKey = localStorage.getItem('jwt_token');
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/pdf',
'Authorization' : this.authKey,
responseType : 'blob',
Accept : 'application/pdf',
observe : 'response'
})
};
return this.http
.get("http://localhost:9989/api/download/help/pdf2", httpOptions);
}
and invocation
this.downloadService.getPdf()
.subscribe((resultBlob: Blob) => {
var downloadURL = URL.createObjectURL(resultBlob);
window.open(downloadURL);});
I resolved it as follows:
// header.component.ts
this.downloadService.getPdf().subscribe((data) => {
this.blob = new Blob([data], {type: 'application/pdf'});
var downloadURL = window.URL.createObjectURL(data);
var link = document.createElement('a');
link.href = downloadURL;
link.download = "help.pdf";
link.click();
});
//download.service.ts
getPdf() {
const httpOptions = {
responseType: 'blob' as 'json')
};
return this.http.get(`${this.BASE_URL}/help/pdf`, httpOptions);
}
I solved the issue in this way (please note that I have merged multiple solutions found on stack overflow, but I cannot find the references. Feel free to add them in the comments).
In My service I have:
public getPDF(): Observable<Blob> {
//const options = { responseType: 'blob' }; there is no use of this
let uri = '/my/uri';
// this.http refers to HttpClient. Note here that you cannot use the generic get<Blob> as it does not compile: instead you "choose" the appropriate API in this way.
return this.http.get(uri, { responseType: 'blob' });
}
In the component, I have (this is the part merged from multiple answers):
public showPDF(fileName: string): void {
this.myService.getPDF()
.subscribe(x => {
// It is necessary to create a new blob object with mime-type explicitly set
// otherwise only Chrome works like it should
var newBlob = new Blob([x], { type: "application/pdf" });
// IE doesn't allow using a blob object directly as link href
// instead it is necessary to use msSaveOrOpenBlob
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(newBlob, fileName);
return;
}
// For other browsers:
// Create a link pointing to the ObjectURL containing the blob.
const data = window.URL.createObjectURL(newBlob);
var link = document.createElement('a');
link.href = data;
link.download = fileName;
// this is necessary as link.click() does not work on the latest firefox
link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
setTimeout(function () {
// For Firefox it is necessary to delay revoking the ObjectURL
window.URL.revokeObjectURL(data);
link.remove();
}, 100);
});
}
The code above works in IE, Edge, Chrome and Firefox. However, I don't really like it, as my component is pulluted with browser specific stuff which will surely change over time.
For Angular 12+, I came up with something like this:
this.ApiService
.getFileFromApi()
.pipe(take(1))
.subscribe((response) => {
const downloadLink = document.createElement('a');
downloadLink.href = URL.createObjectURL(new Blob([response.body], { type: response.body.type }));
const contentDisposition = response.headers.get('content-disposition');
const fileName = contentDisposition.split(';')[1].split('filename')[1].split('=')[1].trim();
downloadLink.download = fileName;
downloadLink.click();
});
The subscribe is on a simple get() with the Angular HttpClient.
// api-service.ts
getFileFromApi(url: string): Observable<HttpResponse<Blob>> {
return this.httpClient.get<Blob>(this.baseApiUrl + url, { observe: 'response', responseType: 'blob' as 'json'});
}
You can do it with angular directives:
#Directive({
selector: '[downloadInvoice]',
exportAs: 'downloadInvoice',
})
export class DownloadInvoiceDirective implements OnDestroy {
#Input() orderNumber: string;
private destroy$: Subject<void> = new Subject<void>();
_loading = false;
constructor(private ref: ElementRef, private api: Api) {}
#HostListener('click')
onClick(): void {
this._loading = true;
this.api.downloadInvoice(this.orderNumber)
.pipe(
takeUntil(this.destroy$),
map(response => new Blob([response], { type: 'application/pdf' })),
)
.subscribe((pdf: Blob) => {
this.ref.nativeElement.href = window.URL.createObjectURL(pdf);
this.ref.nativeElement.click();
});
}
// your loading custom class
#HostBinding('class.btn-loading') get loading() {
return this._loading;
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
}
In the template:
<a
downloadInvoice
[orderNumber]="order.number"
class="btn-show-invoice"
>
Show invoice
</a>
My answer is based on #Yennefer's, but I wanted to use the file name from the server since I didn't have it in my FE. I used the Content-Disposition header to transmit this, since that is what the browser uses for a direct download.
First, I needed access to the headers from the request (notice the get method options object):
public getFile(): Observable<HttpResponse<Blob>> {
let uri = '/my/uri';
return this.http.get(uri, { responseType: 'blob', observe: 'response' });
}
Next, I needed to extract the file name from the header.
public getFileName(res: HttpResponse<any>): string {
const disposition = res.headers.get('Content-Disposition');
if (!disposition) {
// either the disposition was not sent, or is not accessible
// (see CORS Access-Control-Expose-Headers)
return null;
}
const utf8FilenameRegex = /filename\*=UTF-8''([\w%\-\.]+)(?:; |$)/;
const asciiFilenameRegex = /filename=(["'])(.*?[^\\])\1(?:; |$)/;
let fileName: string = null;
if (utf8FilenameRegex.test(disposition)) {
fileName = decodeURIComponent(utf8FilenameRegex.exec(disposition)[1]);
} else {
const matches = asciiFilenameRegex.exec(disposition);
if (matches != null && matches[2]) {
fileName = matches[2];
}
}
return fileName;
}
This method checks for both ascii and utf-8 encoded file names, prefering utf-8.
Once I have the file name, I can update the download property of the link object (in #Yennifer's answer, that's the lines link.download = 'FileName.ext' and window.navigator.msSaveOrOpenBlob(newBlob, 'FileName.ext');)
A couple of notes on this code:
Content-Disposition is not in the default CORS whitelist, so it may not be accessible from the response object based on the your server's configuration. If this is the case, in the response server, set the header Access-Control-Expose-Headers to include Content-Disposition.
Some browsers will further clean up file names. My version of chrome seems to replace : and " with underscores. I'm sure there are others but that's out of scope.
//Step: 1
//Base Service
this.getPDF() {
return this.http.get(environment.baseUrl + apiUrl, {
responseType: 'blob',
headers: new HttpHeaders({
'Access-Control-Allow-Origin': '*',
'Authorization': localStorage.getItem('AccessToken') || ''
})
});
}
//Step: 2
//downloadService
getReceipt() {
return new Promise((resolve, reject) => {
try {
// {
const apiName = 'js/getReceipt/type/10/id/2';
this.getPDF(apiName).subscribe((data) => {
if (data !== null && data !== undefined) {
resolve(data);
} else {
reject();
}
}, (error) => {
console.log('ERROR STATUS', error.status);
reject(error);
});
} catch (error) {
reject(error);
}
});
}
//Step 3:
//Component
getReceipt().subscribe((respect: any) => {
var downloadURL = window.URL.createObjectURL(data);
var link = document.createElement(‘a’);
link.href = downloadURL;
link.download = “sample.pdf";
link.click();
});
This also works in IE and Chrome, almost the same answer only for other browsers the answer is a bit shorter.
getPdf(url: string): void {
this.invoiceService.getPdf(url).subscribe(response => {
// It is necessary to create a new blob object with mime-type explicitly set
// otherwise only Chrome works like it should
const newBlob = new Blob([(response)], { type: 'application/pdf' });
// IE doesn't allow using a blob object directly as link href
// instead it is necessary to use msSaveOrOpenBlob
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(newBlob);
return;
}
// For other browsers:
// Create a link pointing to the ObjectURL containing the blob.
const downloadURL = URL.createObjectURL(newBlob);
window.open(downloadURL);
});
}

jQuery file upload Resuming file uploads

I am using the Jquery file upload basic-plus.html. I am not sure How to use the Resumable uploading functionality in the below code.
I see something like this according to the documentation but not sure How to use that with the basic-plus.html
$('#fileupload').fileupload({
maxChunkSize: 10000000, // 10 MB
add: function (e, data) {
var that = this;
$.getJSON('server/php/', {file: data.files[0].name}, function (result) {
var file = result.file;
data.uploadedBytes = file && file.size;
$.blueimp.fileupload.prototype
.options.add.call(that, e, data);
});
}
});
I tried something like below. But didn't work.
basic-plus.html
$(function () {
'use strict';
// Change this to the location of your server-side upload handler:
var url = window.location.hostname === 'blueimp.github.io' ?
'//jquery-file-upload.appspot.com/' : 'server/php/',
uploadButton = $('<button/>')
.addClass('btn btn-primary')
.prop('disabled', true)
.text('Processing...')
.on('click', function () {
var $this = $(this),
data = $this.data();
$.getJSON('server/php/', {file: data.files[0].name}, function (result) {
console.log('come here');
console.log(result);
var file = result.file;
data.uploadedBytes = file && file.size;
//$.blueimp.fileupload.prototype.options.add.call($this, data);
});
$this
.off('click')
.text('Abort')
.on('click', function () {
$this.remove();
data.abort();
});
data.submit().always(function () {
$this.remove();
});
});
$('#fileupload').fileupload({
url: url,
dataType: 'json',
autoUpload: false,
//multipart: false,
acceptFileTypes: /(\.|\/)(avi|flv|wmv|mpg|mp4|mov|3gp|m4v)$/i,
maxFileSize: 969932800, // 900 MB
maxChunkSize: 2000000, // 2 MB
// Enable image resizing, except for Android and Opera,
// which actually support image resizing, but fail to
// send Blob objects via XHR requests:
disableImageResize: /Android(?!.*Chrome)|Opera/
.test(window.navigator.userAgent),
previewMaxWidth: 100,
previewMaxHeight: 100,
previewCrop: true,
}).on('fileuploadadd', function (e, data) {
data.context = $('<div/>').appendTo('#files');
$.each(data.files, function (index, file) {
var node = $('<p/>').append($('<span/>').text(file.name));
console.log(node);
if (!index) {
node
.append('<br>')
.append(uploadButton.clone(true).data(data));
}
node.appendTo(data.context);
});
}).on('fileuploadprocessalways', function (e, data) {
var index = data.index,
file = data.files[index],
node = $(data.context.children()[index]);
if (file.preview) {
node
.prepend('<br>')
.prepend(file.preview);
}
if (file.error) {
node
.append('<br>')
.append($('<span class="text-danger"/>').text(file.error));
}
if (index + 1 === data.files.length) {
data.context.find('button')
.text('Upload')
.prop('disabled', !!data.files.error);
}
}).on('fileuploadprogressall', function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#progress .progress-bar').css(
'width',
progress + '%'
);
}).on('fileuploaddone', function (e, data) {
$.each(data.result.files, function (index, file) {
if (file.url) {
var link = $('<a>')
.attr('target', '_blank')
.prop('href', file.url);
$(data.context.children()[index])
.wrap(link);
} else if (file.error) {
var error = $('<span class="text-danger"/>').text(file.error);
$(data.context.children()[index])
.append('<br>')
.append(error);
}
});
}).on('fileuploadfail', function (e, data) {
$.each(data.files, function (index) {
var error = $('<span class="text-danger"/>').text('File upload failed.');
$(data.context.children()[index])
.append('<br>')
.append(error);
});
}).prop('disabled', !$.support.fileInput)
.parent().addClass($.support.fileInput ? undefined : 'disabled');
});

Uploading hundreds of photos (almost a thousand) using ionic

I've been struggling for months to do this but it seems impossible.
I am creating an app using ionic framework which uploads hundreds of photos.
This app is used to generate reports which contains a lot of photos.
The APIs work perfectly on a local server but when I tried using our cloud server much photos are not getting uploaded, the app shows success but when I check the server only few photos are getting uploaded (less than a hundred).
Any ideas about what should I do to make this work?
Thanks.
EDIT:
here's the code for capturing photos cameraservice.js
app.factory('cameraService', function ($rootScope, $q, $http, $location, $timeout, $cordovaCamera,$cordovaFile,$cordovaFileTransfer, apiUrl) {
var settings = {
saveToPhotoAlbum: true,
correctOrientation: true,
quality: 10,
targetWidth: 720,
targetHeight: 720,
};
return {
getPicture: function(){
var d = $q.defer();
let options = {
popoverOptions: CameraPopoverOptions
};
angular.extend(options, settings)
$cordovaCamera.getPicture(options).then(function(imageData) {
let namePath = imageData.substr(0, imageData.lastIndexOf('/') + 1);
let filename = imageData.replace(/^.*[\\\/]/, '');
$cordovaFile.moveFile(namePath, filename, cordova.file.dataDirectory, filename)
.then(function (res) {
d.resolve({ filename: res.name });
}, function (error) {
console.log(error)
});
}, function(err) {
console.log(err)
});
return d.promise;
}
}
})
and here's my uploadservice.js
app.factory('imageUploadService', function ($cordovaFileTransfer) {
var settings = {
fileKey: "file",
chunkedMode: false,
mimeType: "multipart/form-data",
headers : {
Connection:"close"
}
};
return {
upload: function(url, filename, options){
let filePath = cordova.file.dataDirectory + filename;
angular.extend(options, settings);
console.log(url, filePath, options)
return $cordovaFileTransfer.upload(url, filePath, options);
}
}
});
this is how I use the APIs sendservice.js
app.factory('sendService', function ($http, $q, imageUploadService, $timeout, apiUrl) {
return {
photos: function(id, data){
let d = $q.defer();
var url = apiUrl + "/api/senddescription"
var api = apiUrl + "/api/senddetailedphoto";
let q = [];
angular.forEach(data, (item, index)=>{
angular.forEach(item.photos, (i)=>{
let origName = i.image;
var options = {
filename: i.image,
params : {
report_no : id,
label: i.label,
photo_count: index,
photo_label: i.label
},
chunkedMode: false,
headers : {
Connection : "close"
}
};
setTimeout(function(){
q.push(imageUploadService.upload(api, origName, options))
},15000);
})
let data = {
report_no: id,
photo_count: index,
product_description: item.product_description
}
q.push($http.post(url, data));
$q.all(q).then(res=>{
d.resolve(res);
}, err=>{
d.reject(err);
})
})
return d.promise;
}
}
});
These are my APIs
/api/senddescription
public function sendPhotoDescription(Request $request){
$desc = DetailedPhotoDescription::where('report_number',$request->input('report_no'))->where('photo_count',$request->input('photo_count'))->first();
if (!$desc) {
$desc = new DetailedPhotoDescription();
$desc->report_number = $request->input('report_no');
}
$desc->photo_count = $request->input('photo_count');
$desc->product_description = $request->input('product_description');
if ($desc->save()) {
return response()->json([
'message'=>'OK'
],200);
}else{
return response()->json([
'message'=>'Error submitting photo. Please resend the report!'
],500);
}
}
/api/senddetailedphoto
public function sendDetailedPhoto(Request $request){
$file = $request->file('file');
//set a unique file name
$filename = uniqid() . '.' . $file->getClientOriginalExtension();
// //move the files to the correct folder
if ($file->move('images/reports/'. $request->input('report_no').'/detailedPhoto'.'/'.$request->input('photo_count').'/', $filename)) {
$detailed = new DetailedPhoto();
$detailed->report_number = $request->input('report_no');
$detailed->photo_count = $request->input('photo_count');
$detailed->photo_label = $request->input('photo_label');
$detailed->image_data = $filename;
if ($detailed->save()) {
return response()->json([
'message' => 'OK'
],200);
}else{
return response()->json([
'message' => 'Error saving detailed photos. Please resend the report!'
],500);
}
}else{
return response()->json([
'message' => 'Error uploading detailed photos. Please resend the report!'
],500);
}
}

Insert Image to database using typescript (angular2) and spring boot (spring data)

I start by presenting my client side the service
addImage (url: string, params: string[], files: File[]): Observable {
return Observable.create(observer => {
let formData: FormData = new FormData(),
xhr: XMLHttpRequest = new XMLHttpRequest();
for (let i = 0; i < files.length; i++) {
formData.append("uploads[]", files[i], file
s[i].name);
}
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
observer.next(JSON.parse(xhr.response));
observer.complete();
} else {
observer.error(xhr.response);
}
}
};
xhr.upload.onprogress = (event) => {
this.progress = Math.round(event.loaded / event.total * 100);
this.progressObserver.next(this.progress);
};
xhr.open('POST', url, true);
xhr.send(formData);
});
}
then this is my html code
<input type="file" (change)="uploadImage($event)"/>
where I call this method from my component
uploadImage(event) {
var files = event.srcElement.files;
console.log(files);
this._serviceSection.addImage('http://localhost:8080/template/img', [], files).subscribe(() => {
console.log('sent');
});
}
and in my service side
this is a method from my controller
#RequestMapping(value = "/img", method = RequestMethod.POST)
public void getFileContents(#RequestParam MultipartFile file) {
System.out.println("++++++++++++++++++++++++++++++++++++++++ " +file.getOriginalFilename());
}
in a first time a try just to show a fileName but I get this error
It seems that your progressObserver isn't set. The reason for this could be that you didn't subscribe to its associated observable. Don't forget that observables are lazy and if you don't subscribe to them, their initialization callback isn't called.
To prevent from having the error, you could check if it's null or not:
xhr.upload.onprogress = (event) => {
if (this.progressObserver) {
this.progress = Math.round(event.loaded / event.total * 100);
this.progressObserver.next(this.progress);
}
};
Otherwise, you can notice that from RC2, Angular2 accepts FormData objects as parameters of HTTP methods...

jQuery FileUpload: Ajax freezes the browser when uploading images (jpg, png)

I use jQuery Fileupload plugin for uploading files (.pdf,.zip,.dll and .png/.jpg) to server from local. All of file types above can be uploaded successfully on major browsers Chrome/Firefox/IE, except .png/.jpg.
When trying to upload the .png/.jpg on Chrome, the upload plugin will freeze this browser for 10-15 minutes until the ajax of sending data of XHR object is done, even the size of image is quite small (~90Kb). On contrast, the same process just takes 1-2 seconds to be done on FF/IE.
I am using v5.9 of this plugin with these overwrite options:
var maxFileSize = 500000000000000;
var resizeMaxWidth = 1920;
var resizeMaxHeight = 1200;
var maxChunkSize = 1073741824;
var maxNumberOfFiles = 1;
$('#fileupload').fileupload('option', {
forceIframeTransport: true,
maxFileSize: maxFileSize,
resizeMaxWidth: resizeMaxWidth,
resizeMaxHeight: resizeMaxHeight,
maxChunkSize: maxChunkSize,
xhrFields: {
withCredentials: true
},
acceptFileTypes: regularExpression,
autoUpload: autoUpload
});
I tried to set async: true; to force browser not to freeze the page, but failed.
and I got freezing page on Chrome when the scripts run to _onSend() event and can not return "success" callback.
_onSend: function (e, data) {
var that = this,
jqXHR,
slot,
pipe,
options = that._getAJAXSettings(data),
send = function (resolve, args) {
that._sending += 1;
jqXHR = jqXHR || (
(resolve !== false &&
that._trigger('send', e, options) !== false &&
(that._chunkedUpload(options) || $.ajax(options))) ||
that._getXHRPromise(false, options.context, args)
).success(function (result, textStatus, jqXHR) {
that._onDone(result, textStatus, jqXHR, options);
}).fail(function (jqXHR, textStatus, errorThrown) {
that._onFail(jqXHR, textStatus, errorThrown, options);
}).always(function (jqXHRorResult, textStatus, jqXHRorError) {
that._sending -= 1;
that._onAlways(
jqXHRorResult,
textStatus,
jqXHRorError,
options
);
if (options.limitConcurrentUploads &&
options.limitConcurrentUploads > that._sending) {
// Start the next queued upload,
// that has not been aborted:
var nextSlot = that._slots.shift();
while (nextSlot) {
if (!nextSlot.isRejected()) {
nextSlot.resolve();
break;
}
nextSlot = that._slots.shift();
}
}
});
return jqXHR;
};
this._beforeSend(e, options);
if (this.options.sequentialUploads ||
(this.options.limitConcurrentUploads &&
this.options.limitConcurrentUploads <= this._sending)) {
if (this.options.limitConcurrentUploads > 1) {
slot = $.Deferred();
this._slots.push(slot);
pipe = slot.pipe(send);
} else {
pipe = (this._sequence = this._sequence.pipe(send, send));
}
// Return the piped Promise object, enhanced with an abort method,
// which is delegated to the jqXHR object of the current upload,
// and jqXHR callbacks mapped to the equivalent Promise methods:
pipe.abort = function () {
var args = [undefined, 'abort', 'abort'];
if (!jqXHR) {
if (slot) {
slot.rejectWith(args);
}
return send(false, args);
}
return jqXHR.abort();
};
return this._enhancePromise(pipe);
}
return send();
},
Do you know how to force this plugin's Ajax to run on Chrome as it does on Firefox/IE ? or any hints to fix this issue ?
Thank you !
Cheers,