I am using fine uploader to handle the uploading of files in a web application I have. Is there some sort of callback for when the last file has finished processing? I found the onComplete callback, but this is fired when every file completes. I need to know when all files are done. Does anyone know of a way to do this with fine uploader?
I don't think fine uploader provides what you're asking for, but it's easy to do this yourself. You can increment a count in the onSubmit callback, and decrement it in the onComplete callback. When the count reaches 0 in onComplete, that means all the files have processed.
Ended up going this route:
var uploader = $("#upload").fineUploader({
request: {
endpoint: postUrl
},
template: uploadTemplate
}).on('submit',function(){
fileCount++;
}).on('complete', function (event, id, name, responseJSON) {
fileCount--;
if(fileCount == 0){
alert("done!");
}
});
Related
For around 3 weeks I've been working on an Electron app and finally decided to get around to adding update checking. For my research, the standard way to do this in Electron (using Squirrel) requires the user to physically install the application onto their computer. I would rather not do this, and keep everything as portable as possible. I then decided to try making my own update script by having the program download the update.zip, and extract it to overwrite the existing files. This works well, up until the very end. At the very end of the extraction, I receive a Invalid package error, and the actual app.asar file is missing, rendering the application useless.
I am using this to download and extract the updates:
function downloadFile(url, target, fileName, cb) { // Downloads
var req = request({
method: 'GET',
uri: url
});
var out = fs.createWriteStream(target+'/'+fileName);
req.pipe(out);
req.on('end', function() {
unzip(target+'/'+fileName, target, function() {
if (cb) {
cb();
}
});
});
}
function unzip(file, target, cb) { // Unzips
var out = fs.createReadStream(file);
out.pipe(unzipper.Extract({ path: target })).on('finish', function () {
dialog.showMessageBox({
type: 'question',
message: 'Finished extracting to `'+target+'`'
});
if (cb) {
cb();
}
});
}
And call it with:
downloadFile('http://example.com/update.zip', path.join(__dirname, './'), 'update.zip', function() { // http://example.com/update.zip is not the real source
app.relaunch();
app.quit();
});
And I use the unzipper NPM package (https://www.npmjs.com/package/unzipper).
The code works perfectly for all other zips, but it fails when trying to extract a zip containing an Electron app.
Anything I'm doing wrong, or maybe a different package that properly supports extracting zips with .asar files?
Edit 1
I just found https://www.npmjs.com/package/electron-basic-updater, which does not throw the same JavaScript error however it still does not extract the .asar files correctly, and will throw it's own error. Since the .asar is still missing, the app is still useless after the "update"
Thanks to your link to electron-basic-updater, I have found this issue mentioned there: https://github.com/TamkeenLMS/electron-basic-updater/issues/4.
They refer to the issue in the electron app: https://github.com/electron/electron/issues/9304.
Finally, in the end of the second topic there's a solution:
This is due to the electron fs module treating asar files as directories rather than files. To make the unzip process work you need to do one of two things:
Set process.noAsar = true
Use original-fs instead of fs
I have seen the people working with original-fs. But it looked like a big trouble to me.
So I tried setting process.noAsar = true (and then process.noAsar = false after unzipping) - and that worked like a charm.
I'm coding a script in nodejs to automatically retrieve data from an online directory.
Knowing that I had never done this, I chose javascript because it is a language I use every day.
I therefore from the few tips I could find on google use request with cheerios to easily access components of dom of the page.
I found and retrieved all the necessary information, the only missing step is to recover the link to the next page except that the one is generated 4 seconds after loading of page and link contains a hash so that this step Is unavoidable.
What I would like to do is to recover dom of page 4-5 seconds after its loading to be able to recover the link
I looked on the internet, and much advice to use PhantomJS for this manipulation, but I can not get it to work after many attempts with node.
This is my code :
#!/usr/bin/env node
require('babel-register');
import request from 'request'
import cheerio from 'cheerio'
import phantom from 'node-phantom'
phantom.create(function(err,ph) {
return ph.createPage(function(err,page) {
return page.open(url, function(err,status) {
console.log("opened site? ", status);
page.includeJs('http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', function(err) {
//jQuery Loaded.
//Wait for a bit for AJAX content to load on the page. Here, we are waiting 5 seconds.
setTimeout(function() {
return page.evaluate(function() {
var tt = cheerio.load($this.html())
console.log(tt)
}, function(err,result) {
console.log(result);
ph.exit();
});
}, 5000);
});
});
});
});
but i get this error :
return ph.createPage(function (page) {
^
TypeError: ph.createPage is not a function
Is what I am about to do is the best way to do what I want to do? If not what is the simplest way? If so, where does my error come from?
If You dont have to use phantomjs You can use nightmare to do it.
It is pretty neat library to solve problems like yours, it uses electron as web browser and You can run it with or without showing window (You can also open developer tools like in Google Chrome)
It has only one flaw if You want to run it on server without graphical interface that You must install at least framebuffer.
Nightmare has method like wait(cssSelector) that will wait until some element appears on website.
Your code would be something like:
const Nightmare = require('nightmare');
const nightmare = Nightmare({
show: true, // will show browser window
openDevTools: true // will open dev tools in browser window
});
const url = 'http://hakier.pl';
const selector = '#someElementSelectorWitchWillAppearAfterSomeDelay';
nightmare
.goto(url)
.wait(selector)
.evaluate(selector => {
return {
nextPage: document.querySelector(selector).getAttribute('href')
};
}, selector)
.then(extracted => {
console.log(extracted.nextPage); //Your extracted data from evaluate
});
//this variable will be injected into evaluate callback
//it is required to inject required variables like this,
// because You have different - browser scope inside this
// callback and You will not has access to node.js variables not injected
Happy hacking!
I'm trying to implement an upload form and return the upload status to return tot he user using xhr. Everything seems to be implemented correctly, however when uploading, the callbacks seem to occur way too quick and return a much higher percentage than has actually occurred.
With files ~<20Mb, I get a callback immediately which shows over 99% while the upload continues to churn away for some time in the background.
See the below screengrab showing the console from a 74Mb file. This was taken a couple of seconds after the upload was initialised and the upload continued for another ~60 seconds (notice just 3 callbacks registering (loaded totalsize) (calculatedpercentage) and the ajax upload continuing with the throbber).
Has anyone experienced this and managed to get an acurate representation of upload status?
(the 'load' event triggers correctly after the upload process)
Here's my code:
$(this).ajaxSubmit({
target: '#output',
beforeSubmit: showRequest,
xhr: function()
{
myXhr = $.ajaxSettings.xhr();
if (myXhr.upload)
{
console.log('have xhr');
myXhr.upload.addEventListener('progress', function(ev){
if (ev.lengthComputable) {
console.log(ev.loaded + " " + ev.total);
console.log((ev.loaded / ev.total) * 100 + "%");
}
}, false);
}
return myXhr;
},
dataType: 'json',
success: afterSuccess
});
There are several reports of the same behavior - incorrect progress report on file upload - caused by antivirus software checking the files to be uploaded. My guess is that some part of antivirus attempts to make up for possible delay (caused by the check) - and fails to do it properly.
I had the same issue recently. I think your ajax call is simply returned before your file uploads. To work around this load back what you uploaded and check for the load event. For example, if you are uploading an image (using jQuery):
var loadCheck = $('<img src="' + uploadedUrl +'">').hide().appendTo('body');
loadCheck.on('load', updateProgressBar());
of Course you can implement it on other type files, and incorporate an $.each iteration.
I'm using dropzone.js to upload certain files to my server. I have the problem that sometimes the server isn't able to keep up with the connections and refuses some uploads so they will fail and get marked red with an x. I would like to automaticaly retry after a certain amount of time or at least give the user the ability to restart it manually.
Is there an implemented feature in dropzone.js, an easy enough way to implement it for myself or is there a better tool to do those kinda uploads via drag/drop, preview, ajax, etc...?
My solution is without changing the Dropzone library and only 4 lines long. I try the file upload two times because the first failed request sets a new cookie based CSRF token:
var isFirstTry = true;
myDropzone = new Dropzone(document.body, {
init: function() {
this.on("sending", function(file, xhr, formData) {
xhr.setRequestHeader("X-CSRF", Cookies.get('CSRF'));
});
},
error: function(file, errorMessage, xhr){
if (errorMessage && errorMessage.status === 405 && file && isFirstTry) {
isFirstTry = false;
//remove item from preview
this.removeFile(file)
//duplicate File objet
new File([file], file.name, { type: file.type });
this.uploadFile(file);
}
},
// other configs
});
After dropzone error event, dropzone fires complete event no matter what is the result. On complete dropzone set the status element to be complete. This hide the progress bar. To prevent this behavior, copy the File object. This prevent complete hook to handle the new preview element.
One small modification to dropzone.js is required to make things look pretty but otherwise its just a directive.
My dropzone now retries (infinitely, but I'll fix that later) until it succeeds. A little more work is required to reset the progress bars but this should be enough to get you somewhere (if you still care about this).
The edit to dropzone.js is (in the beautified version):
success: function(file) {
file.previewElement.classList.remove("dz-error");
return file.previewElement.classList.add("dz-success");
}
Where I've added the remove line. This changes Xs to ticks when a file successfully uploads.
The angular directive follows:
.directive('dropZone', function($rootScope) {
return function ($scope, element, attr) {
var myDropZone = element.dropzone({
url: "api/ImageUpload",
maxFilesize: 100,
paramName: "uploadfile",
maxThumbnailFilesize: 5,
autoProcessQueue: false,
parallelUploads: 99999,
uploadMultiple: false,
// this is my identifier so my backend can index the images together
params: {identifier: $scope.identifier},
// I seem to need to do this when a file is added, otherwise it doesn't update
init: function(){this.on("addedfile", function(file){$rootScope.$digest();})}
});
// grabbing the dropzone object and putting it somewhere the controller can reach it
$scope.dropZone = myDropZone.context.dropzone;
// what we use to work out if we're _really_ complete
$scope.errors = [];
// here is our retry mechanism
myDropZone.context.dropzone.addEventListener("error", function(file,errorMessage,xhr)
{
// log our failure so we don't accidentally complete
$scope.errors.push(file.name);
// retry!
myDropZone.context.dropzone.uploadFile(file);
});
myDropZone.context.dropzone.addEventListener("success", function(file,errorMessage,xhr)
{
// remove from the error list once "success" (_not_ "complete")
$scope.errors.splice($scope.errors.indexOf(file.name), 1);
});
// this gets called multiple times because of our "retry"
myDropZone.context.dropzone.addEventListener("queuecomplete", function()
{
// if we're here AND have no errors we're done
if($scope.errors.length == 0)
{
// this is my callback to the controller to state we're all done
$scope.uploadComplete();
}
});
};
})
not sure if all that myDropZone.context.dropZone stuff is necessary, I kinda suck at javascript and spend a lot of my time console.logging() objects and examining them in the debugger. This is where I found the dropzone component, perhaps there is an easier way?
My situation was a little bit different then Quibblesome, but my solution was based on their answer... so thanks Quibblesome!!!!
On my situation the ajax wasn't failing so dropzone.addEventListener("error", function(file,errorMessage,xhr) was never getting triggered. So I changed Quibblsomes solution a bit to work even if dropdzone triggered success.
var fileObj;
clientDetailsDropZone = new Dropzone($("#clientDetailsDropZoneArea").get(0), {
init: function()
{
this.on("success", function(e,response)
{
//IF THE USERS authtoken is expired..... retry the upload automatically
if(!authToken.isValid)
{
//Get a new Token and then autmoatically re upload -- getFileAuthToken is another ajax call that authorizes the user
getFileAuthToken(function f(e){
this.uploadFile(fileObj);
});
}
else
{ //They had a good token and the upload worked
alert("yay your upload worked!");
}
});
this.on("addedfile", function(file) {
fileObj = file;
});
}
});
For some reason, in the following code, evt.target.result is empty. Why is that?
function drop(evt) {
evt.stopPropagation();
evt.preventDefault();
var file = evt.dataTransfer.files[0];
handleFiles(file, evt.target);
}
function handleFiles(file, target) {
loadSongAnimate();
var reader = new FileReader();
// init the reader event handlers
reader.onloadend = handleReaderLoadEnd;
// begin the read operation
reader.readAsDataURL(file);
}
function handleReaderLoadEnd(evt) {
alert('Passing this: ' + evt.target.result);
document.getElementById('audioTagId').src = evt.target.result;
}
From the fine manual:
onloadend
Called when the read is completed, whether successful or not. This is called after either onload or onerror.
I suspect that you have an error condition. Add an onerror callback and have a look at what reader.error has to say. You might want to use separate onerror, onabort, and onload callbacks instead of onloadend:
onabort
Called when the read operation is aborted.
onerror
Called when an error occurs.
onload
Called when the read operation is successfully completed.
That might make it easier to handle the individual events.
In your comment you say that you're getting an "error 2", from the other fine manual:
Constant: SECURITY_ERR
Value: 2
Description: The file could not be accessed for security reasons.
So it looks like you getting a "permission denied" error.
I was editing and viewing the file over a local file:// protocol. When you are referencing a local file inside another local file, the blank headers in the referenced local file with throw security errors.
Lesson learned... always upload to a server for testing as well. Would have saved me hours of Googling, and lots of hair.