Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
133 views
in Technique[技术] by (71.8m points)

javascript - JS FileReader duplicating itself with previous values

I am quite new to JS promises and while working with them I got into a problem. First, let me explain what I am trying to achieve and what is getting achieved. I was creating a function that creates a file type input element that accepts images and then listens to onchange event handler on that element. When the user selects an image I call .then() method to resolve a promise which uses FileReader() to extract base64 of the image. What happens is that when I try to add the image again using that function the older image gets added as well. This repetition keeps on happening with the amount of older images already added. This is my code so far,

const imageInput = document.createElement('input');
imageInput.setAttribute('accept', 'image/*');
imageInput.setAttribute('type', 'file');

imageInput.onchange = () => {
    const imageFile = imageInput.files[0];
    if (/^image//.test(imageFile.type)) 
    {
        getBase64(imageFile).then(
            data => insertImage(data)
        );                        
    } 
    else 
    {
        console.warn('You could only upload images.');
    }
};

function clearImageInput() {
    imageInput.value = '';
}

function handleImage(){
    clearImageInput();
    imageInput.click();
}

function getBase64(file) 
{
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => resolve(reader.result);
        reader.onerror = error => reject(error);
    });
}

function insertImage(base64_string)
{
    // This function basically inserts the image into the Quill Editor.
    // But if I insert an Image A first and then try to insert Image B
    // Meaning basically I only called handleImage() twice but
    // It will insert in this pattern:
    // -> Image A
    // -> Image A + Image B

    // Follwing click handler is was being executed more than once
    // I added .unbind() before .click() to resolve the issue

    $(".some-btn").click(function(){
        var altText = "My Text";
        var titleText = "My Text";
        if(altText != "" && titleText != "")
        {
            let range = quill.getSelection(true);
            quill.insertText(range.index, '
', Quill.sources.USER);
            quill.insertEmbed(range.index + 1, 'image', {
                alt: altText,
                url: baseString,
                title: titleText
            }, Quill.sources.USER);
            quill.setSelection(range.index + 2, Quill.sources.SILENT);
         }
         else
         {
             alert("Input the details!");
         }
     });
}

The code above is basically is used to overwrite the default methods of the WYSIWYG HTML editor. So when I click on the add image button on the editor I call handleImage() function which then processes image upload. Now, this scenario is actually happening: When I add an image a the function works perfectly fine and gives me the base64 of that image which in turn I insert into the editor. But when I try to add image b First the function will give base64 of image a then it'll give the base64 of image b. The function basically duplicates itself. And this problem keeps on duplicating when I add more images. As far as the calling of this code is concerned it is called as follows:

var toolbarModule = quill.getModule('toolbar');
toolbarModule.addHandler('image', handleImage);

In above example I am adding an event handler to Quill which is an online JS HTML editor.

question from:https://stackoverflow.com/questions/65921423/js-filereader-duplicating-itself-with-previous-values

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I think this should solve your problem: Basically we should only create the input once and add onchange event once, then just reuse it. then, everytime handleImage is called, we first call clearInput() before opening the file dialog for new selection. In my opinion, instead of this method of having the input only exist in dom but not in the document, you should instead have an input hidden inside of your button (by giving input zero opacity and absolute position with 100% width and height inside of the button, everytime button is clicked file input will trigger. if you want i can demonstrate to you what a file upload using this common pattern looks like.

const imageInput = document.createElement('input');
imageInput.setAttribute('accept', 'image/*');
imageInput.setAttribute('type', 'file');
imageInput.id = "img-inp-tmp";
// Listen upload local image and save to server
imageInput.onchange = () => {
  const imageFile = imageInput.files[0];
  if (/^image//.test(imageFile.type)) 
  {
    getBase64(imageFile).then(
      data => insertImage(data)
    );                        
  } 
  else 
  {
    console.warn('You could only upload images.');
  }
};

function clearInput() {
  imageInput.value = '';// by setting value to empty, we clear the files!
}

function handleImage(){
  clearInput();
  imageInput.click();
}

function getBase64(file) 
{
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = error => reject(error);
    reader.readAsDataURL(file);
  });
}

function insertImage(base64_string)
{
  // This function gets called multiple times based on how much handleImage() was called
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...