Home > Net >  How can I use async / await in my function to wait for the "change" event to fire on a fil
How can I use async / await in my function to wait for the "change" event to fire on a fil

Time:01-28

I want a function which prompts the user to select an image. It should then wait for an image to be selected and then return that image. I want to achieve this without creating a new input element and attaching a new eventlistener every time (atleast not without removing the old ones first) because I expect this button to be used A LOT!

What I have right now is successfully prompting the user can getting the image. But I am not returning it so I can use it however I want after the prompt_for_image() function call. Please help me D:

I added a console log button for testing purposes so you can see the image is being selected propperly.

const images = [];
const file_input = document.createElement('input');
file_input.type = 'file';
file_input.accept = 'image/*';
file_input.addEventListener('change', () => {
  const reader = new FileReader();
  reader.onload = () => images.push(reader.result);
  reader.readAsDataURL(file_input.files[0]);
});

function prompt_for_image() {
  file_input.value = null;
  file_input.click();
}
 document.getElementById('btn_add_new_image').addEventListener('click', async () => {
  await prompt_for_image();
});

document.getElementById('btn_log_images').addEventListener('click', () => { console.log(images) });
<button type='button' id='btn_add_new_image'>ADD NEW IMAGE</button>

<button type='button' id='btn_log_images'>console log image array</button>

CodePudding user response:

You'll need to properly promisify FileReader, then promisify the addEventListener. This is easiest done by using the once parameter:

function readFileAsDataURL(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}
function waitForNextEvent(element, type) {
  return new Promise(resolve => {
    element.addEventListener(type, resolve, {once: true});
  });
}

Now you can do

const images = [];
const fileInput = Object.assign(document.createElement('input'), {
  type: 'file',
  accept: 'image/*',
});

async function promptForImage() {
  const promise = waitForNextEvent(fileInput, 'change');
  fileInput.value = null;
  fileInput.click();
  await promise;
  return fileInput.files[0];
}
document.getElementById('btn_add_new_image').addEventListener('click', async () => {
  images.push(await readFileAsDataURL(await promptForImage()));
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
});
document.getElementById('btn_log_images').addEventListener('click', () => {
  console.log(images);
});


function readFileAsDataURL(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}
function waitForNextEvent(element, type) {
  return new Promise(resolve => {
    element.addEventListener(type, resolve, {once: true});
  });
}
<button type='button' id='btn_add_new_image'>ADD NEW IMAGE</button>

<button type='button' id='btn_log_images'>console log image array</button>

  • Related