Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resolve promise into addEventListener

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...

like image 917
Pierre Burton Avatar asked Aug 10 '17 12:08

Pierre Burton


2 Answers

in 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 */
});
like image 191
Bergi Avatar answered Sep 21 '22 21:09

Bergi


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 */
  });
}
like image 30
Redu Avatar answered Sep 21 '22 21:09

Redu