Is it possible to listen to the upload progress event given by the xhr object?
Normally it is done like this:
xhr.upload.addEventListener('progress', handler);
I know that the xhr object is returned by end() and in the response object. The latter fires only when the response is received though (which makes sense).
Any ideas?
Yes. superagent fires progress events through it's eventemitter.
Basically:
request
.post('/api/file')
.send(someFile)
.on('progress', function(e) {
console.log('Percentage done: ', e.percent);
}
.end(function(res){
if (res.ok) {
alert('yay got ' + JSON.stringify(res.body));
} else {
alert('Oh no! error ' + res.text);
}
});
See https://github.com/visionmedia/superagent/blob/master/lib/client.js#L756-L770
Oh didn't notice the 'on()' method.
Thanks! 馃憤
it's worth mentioning here that the snippet above won't work because "on()" method is after the "end()" call.
@pbc Thanks for the note, but why? Isn't that supposed to be promise?
I think it's by design. This is what you have in the readme:

@rexxars your example doesn't work. Or at least not in my case. I have to call on('progress') before end(), otherwise the handler isn't triggered.
So
request
.post('/api/file')
.send(someFile)
.on('progress', function(e) {
console.log('Percentage done: ', e.percent);
})
.end(function(res){
if (res.ok) {
alert('yay got ' + JSON.stringify(res.body));
} else {
alert('Oh no! error ' + res.text);
}
});
Not using superagent anymore, but based on the previous comments you're probably right. Updated my example.
If anyone else comes across this thread _(it's the default thread for superagent progress tracking on google)_, here's the updated section where the progress event is emitted:
https://github.com/visionmedia/superagent/blob/master/lib/client.js#L780-L799
My question is not directly the same as the question in this thread but how do I pass a different class function as a callback handler for progress? Basically I want to pass a progress function of my React component as a handler for request.on('progress',..) Here is my code:
`progress(obj) {
var percent = obj.percent;
console.log('[progress] Percentage done: ', percent);
if (percent > 100) {
this.setState({completed: 100});
} else {
this.setState({completed: percent});
}
}
onDrop(files) {
console.log('Received files: ', files);
this.state.completed = 0;
var data = new FormData();
var req = request.post('/nltools/v1/files/upload');
files.forEach((file)=> {
data.append('files[]', file, file.name);
});
req.on('progress', this.progress);
req.send(data);
req.end(function(err, res){
console.log("Successfully uploaded");
});
}`
However, I am constantly getting an error: Uncaught TypeError: Cannot read property 'apply' of undefined
@similityman I think that you're digging in to the wrong direction: see
@similityman Have you added this.progress = this.progress.bind(this); to your component's constructor?
@similityman Alternative to @teonik's solution, you can use a bound function (arrow function) when attach the superagent onprogress handler. This can also give you a chance to bind extra params to your onprogress handler if you need references to anything.
// without extra params
req.on( 'progress', event => this.onProgress( event ) );
// with extra reference to the files array
req.on( 'progress', event => this.onProgress( event, files ) );
I personally chose to fire off individual requests for each file upload in my own app so I could render progress per file. I used the second method to bind a uuid to each file so I could map the progress emitted to the correct file in the uploading queue. Not sure how valuable copy/pasting that example will be, but hey... sharing is caring!
// from inside my Uploader component wrapping DropZone...
/**
* Proxied handler function for the DropZone's native 'onDrop' method.
* Called with an array of files uploaded.
* Sets up component state to handle progress bars,
* and uses uuid's to make unique keys on potential
* files with identical names.
*
* @param files
*/
uploadFiles( files ) {
const filesToUpload = files.map( ( file ) => {
return { name: file.name, percent: 0, uuid: uuid.v4(), timestamp: Date.now(), data: file };
} );
this.setState( {
isUploading: true,
files: [ ...this.state.files, ...filesToUpload ],
} );
let promises = filesToUpload.map( file => this.uploadFile( file ) );
Promise.all( promises ).then( () => {
this.setState( { isUploading: false } );
this.onUploadComplete();
} );
}
/**
* By attaching each file to an individual ajax call,
* we are able to bind our unique keys to the progress events
* and render progress on each individual file.
*
* @param file
* @returns {Promise}
*/
uploadFile( file ) {
return (
request.post( this.props.uploadURI )
.attach( file.name, file.data )
.on( 'progress', ( event ) => this.onUploadProgress( file.uuid, event.percent ) )
);
}
Most helpful comment
Yes. superagent fires
progressevents through it's eventemitter.Basically:
See https://github.com/visionmedia/superagent/blob/master/lib/client.js#L756-L770