1

I have struggled for quite a few hours now on the following Problem: I receive an image via input field and need to validate if the ratio is between 1.90 and 1.92. What I need to do is create a Reader, create an Image, get width and height from the loaded image and return true/false.

Now, as mentioned, the file needs loading time and I therefore need some way to process it async. Sadly, I am a total beginner with Promises / Asyncs and need therefore some major help...

The following part is simply the start of my function chain - I check if an image has been uploaded ( radio button is checked .

... 
if (document.editWeb.radio_share[1].checked || document.editWeb.radio_share[2].checked) {
        let promise = processFile();
        promise.then(function(data){
            if (!data){return false;}
        });
}
...

My processFile Function. To my understading this returns a promise, which is why I try to get the promise in the upper code snipped and return a false for the 'data' that I am getting.

async function processFile(){
    try {
        let contentBuffer = await getReader();
        return new Promise((resolve, reject) => {
            let img = new Image;
            img.onload = () => {
            let ratio = img.width / img.height;
                if (ratio > 1.92 ||ratio < 1.90 ){
                    resolve(false);
                }else {
                    resolve(true);
                }

            };

            console.log(contentBuffer);
        })

    } catch(err) {
        console.log(err);
    }

}

The function that lets me get a reader.

function getReader() {
    let x = document.getElementById("share_file").files[0];

    return new Promise((resolve, reject) => {
        let reader = new FileReader();
        reader.onload = () => {
            resolve(reader.result);
        };

        reader.onerror = reject;

        reader.readAsDataURL(x);
    })

As a follow Up: All of this is called in

<input id="saveAndStay" type="submit" name="buttonSaveAndStay" onclick="return checkRequirements(lang , data")>

after which we had

function checkRequirements(lang , data) {
...
if (document.editWeb.radio_share[1].checked === true || document.editWeb.radio_share[2].checked) {
        let promise = processFile();
        promise.then(function(data){
            if (!data){return false;}
        });
    }
}

}

Important to note is, that if data returns false - checkRequirements should also return false in order to stop sending the request to the server and instead alert the user with a "this image has a wrong ratio".

I hope this clears things up.

FoolischEx
  • 89
  • 1
  • 9

1 Answers1

1

You forgot the most important part in the processFile function :)

img.src = contentBuffer;

Working demo:

var fileInput = document.getElementById("share_file");

fileInput.addEventListener('change', function() {
  if ("some boxes are checked blah blah") {
    processFile()
      .then(ok => {
        if (!ok) {
          alert("The ratio needs to be between 1.90 and 1.92");
        } else {
          alert("Everything ok!");
        }
      });
  }
});

function processFile() {
  return getReader()
    .then(dataUrl => {
      return new Promise((resolve, reject) => {
        const img = new Image;
        img.onload = () => {
          let ratio = img.width / img.height;
          resolve(ratio <= 1.92 && ratio >= 1.90);
        };
        img.onerror = reject;
        img.src = dataUrl;
      });
    }).catch(err => {
      console.error(err);
      return false;
    });
}

function getReader() {
  const x = fileInput.files[0];

  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = (e) => resolve(e.target.result);
    reader.onerror = reject;
    reader.readAsDataURL(x);
  })
}
<input type='file' id="share_file" />
<p>Demo files you can try uploading:</p>
<img src="https://i.imgur.com/O4tveTG.jpg" />
<img src="https://i.imgur.com/pMavCF8.jpg" />
blex
  • 24,941
  • 5
  • 39
  • 72
  • I tried this code snipped but it never alerts the client. What I might need to say is , all of this is happening in a onclick function – FoolischEx Jun 29 '20 at 11:06
  • @FoolischEx Do you have a complete example reproducing the issue, so we can try it and see what might fail? I tried creating a working example from the bits and pieces you provided, but maybe your code is different. Note that I made a couple of other changes I didn't mention (like the use of `e.target.result` in the `getReader` function, which seemed to make a difference when I tried it) – blex Jun 29 '20 at 11:13
  • The thing that I missed was this part: , which calls the function checkRequirements(...) which afterwards checks if the radio buttons are set and afterwards calls the processFile function – FoolischEx Jun 29 '20 at 11:16
  • If you cannot provide a full example, it will be hard to debug, I'm kind of blind, here. Try putting some `console.log`s in each step, to see where it breaks – blex Jun 29 '20 at 11:19
  • 1
    I will Update my Code for better visibility. I thought this might help. – FoolischEx Jun 29 '20 at 11:21
  • Oh, I see now. You can't do that. You can't return a Promise and expect the form to be send or not natively based on that. Your code is asynchronous, so it won't return `true` or `false` which is required for this to work. You need to use a trick, here. Always return `false`. Then, do your checks, and if they come back as valid, submit the form programmatically. I have to leave now, but I'll come back in 2 hours, I'll be able to create a demo if you want – blex Jun 29 '20 at 11:31
  • this would be really helpful! I will try my best and comment depending on my progress. Thanks for the hlep until now! – FoolischEx Jun 29 '20 at 11:34
  • 1
    Something along the lines of (pseudo code): `function checkRequirements() { yourAsyncProcess().then(ok => { if(ok) {myForm.submit();} else { alert('invalid'); } }); return false; }` You return `false` no matter what, and if your async process says it's all good, [submit the form](https://stackoverflow.com/a/9855663/1913729) – blex Jun 29 '20 at 11:34
  • Your suggestion works, my only problem now is that the input id that is normally being posted does not get posted now anymore, meaning I have to somehow post a new variable similar to 'id="saveAndStay' that I can check upon. – FoolischEx Jun 29 '20 at 12:40
  • 1
    Working now. Thanks for the great help! – FoolischEx Jun 29 '20 at 13:16
  • 1
    Cool glad you sorted this out – blex Jun 29 '20 at 13:38