I'm actually developping a text editor and just got stuck with an issue regarding the image upload and display method.
What I'm trying to achieve
On the click of a button in the toolbar, the app displays a pop-up for uploading a picture. The user can then drag'n drop the file or click and select the file through his file system. After the image is selected, I send it to the server through ajax which uploads it and stores it in a folder. Once this is done, the server sends a response that the file is okay and ready to use. The function then resolves and the editor adds the proper link to the image.
I tried something that worked while attaching event listeners in the promise.
function uploadImage(editor) {
/* Displays the pop-up */
uploadView.style.display = "block";
var promise = new Promise(function(resolve, reject) {
uploadInput.addEventListener('change', function(event) {
/* ajax call */
resolve(value);
});
dropZone.addEventListener('drop', function(event) {
/* ajax call */
resolve(value);
});
});
promise.then(function(result) {
/* Adds the link */
}, function(err) {
/* handles errors */
});
}
I'm actually developping a text editor and just got stuck with an issue regarding the image upload and display method.
What I'm trying to achieve
On the click of a button in the toolbar, the app displays a pop-up for uploading a picture. The user can then drag'n drop the file or click and select the file through his file system. After the image is selected, I send it to the server through ajax which uploads it and stores it in a folder. Once this is done, the server sends a response that the file is okay and ready to use. The function then resolves and the editor adds the proper link to the image.
I tried something that worked while attaching event listeners in the promise.
function uploadImage(editor) {
/* Displays the pop-up */
uploadView.style.display = "block";
var promise = new Promise(function(resolve, reject) {
uploadInput.addEventListener('change', function(event) {
/* ajax call */
resolve(value);
});
dropZone.addEventListener('drop', function(event) {
/* ajax call */
resolve(value);
});
});
promise.then(function(result) {
/* Adds the link */
}, function(err) {
/* handles errors */
});
}
It's all good, but everytime you trigger the function, a new listener is attached and the function inside runs another time per new click...
I then thought I might remove the listeners after the promise resolves. However, in order to do so, I can't make use of anonymous functions but then I can't use my resolve method inside as it throws an error.
This is not working:
function uploadImage(editor) {
/* Displays the pop-up */
uploadView.style.display = "block";
var promise = new Promise(function(resolve, reject) {
uploadInput.addEventListener('change', handleUpload);
dropZone.addEventListener('drop', handleUpload);
});
promise.then(function(result) {
/* Adds the link */
/* Removes the listeners */
uploadInput.removeEventListener('change', handleUpload);
dropZone.removeEventListener('drop', handleUpload);
}, function(err) {
/* Handles errors */
/* Removes the listeners */
uploadInput.removeEventListener('change', handleUpload);
dropZone.removeEventListener('drop', handleUpload);
});
}
function handleUpload(event) {
if (event.type == "change") {
/* ajax call */
resolve(value); // Throws an error
} else {
/* ajax call */
resolve(value); // Throws an error
}
}
I'm running out of idea...
Share Improve this question edited Jul 16, 2021 at 17:57 John Kugelman 362k69 gold badges548 silver badges594 bronze badges asked Aug 10, 2017 at 12:34 Pierre BurtonPierre Burton 2,0842 gold badges17 silver badges30 bronze badges 1- I can see another issue here, if popup is open and user upload and then change file or drops on dropZone two times then event will fire twice and it will try to resolve a already resolved promise in second attempt. – Manish Mittal Commented Sep 7, 2020 at 4:30
2 Answers
Reset to default 13in order to do so, I can't make use of anonymous functions but then I can't use my resolve method inside
There's no reason to move the function(s) outside of the uploadImage
function or the new Promise
callback when naming them or converting them to declarations:
var promise = new Promise(function(resolve, reject) {
function handleUpload(event) {
/* Removes the listeners */
uploadInput.removeEventListener('change', handleUpload);
dropZone.removeEventListener('drop', handleUpload);
resolve(event); // works just fine
}
uploadInput.addEventListener('change', handleUpload);
dropZone.addEventListener('drop', handleUpload);
});
promise.then(function(event) {
if (event.type == "change") {
return /* ajax call */
} else {
return /* other ajax call */
}
}).then(function(result) {
/* Adds the link */
}, function(err) {
/* Handles errors */
});
ElementTarget.addEventListener()
takes three arguments. The event name, a callback and an options object. Now this options object is interesting and can be handy since it includes a boolean property called once
. What does it do..?
- once: A Boolean indicating that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked.
Cool. Then you may simply change your first snippet as follows;
function uploadImage(editor) {
/* Displays the pop-up */
uploadView.style.display = "block";
var promise = new Promise(function(resolve, reject) {
uploadInput.addEventListener('change', function(event) {
/* ajax call */
resolve(value);
},{once: true}); // remove event after run once
dropZone.addEventListener('drop', function(event) {
/* ajax call */
resolve(value);
},{once: true}); // remove event after run once
});
promise.then(function(result) {
/* Adds the link */
}, function(err) {
/* handles errors */
});
}