Load-Image Library - Reset or Change File

Using the Load-Image library how do I reset the canvas when clearing or change the selection? At the moment I end up with multiple previews if I change the selection … thanks in advance

<html>
<head>
<title>Load Image Test</title>
<meta charset="utf-8">
</head>

<body>
<form>
    <input type="file" id="file-input">
    </form>
    <script src="js/load-image.all.min.js"></script>
    <script>
document.getElementById('file-input').onchange = function (e) {
  loadImage(
    e.target.files[0],
    function (img) {
      document.body.appendChild(img)
    },
    {
     maxWidth: 200,
     orientation: true
    } // Options
  )
}

    </script>
</body>
</html>

Well, appendChild adds a new copy on to the page. What you need to do is to remove the old one before adding a new one.

You can do that by using a div called display, or result, or something meaningful.

    <div id="display"></div>

Now you can get that display area, and clear it, before showing the image.

    function (img) {
      var display = document.querySelector("#display");
      display.innerHTML = "";
      display.appendChild(img);
    },

thanks, I think that works for changing the selection but not of the input is cleared

What keyboard and/or mouse commands do you use to clear the input?

I clicked the input then clicked the cancel button

Okay, so we need to hook in to an event that occurs when the file dialog is cancelled.

It doesn’t seem easy to detect that cancel has occurred, so another potential solution is to clear things when you browse for a file.

When chose-file is clicked, we can clear the display area then and there, which lets us simplify the img function.

document.getElementById('file-input').onclick = function (e) {
  var display = document.querySelector("#display");
  display.innerHTML = "";
};
document.getElementById('file-input').onchange = function (e) {
  loadImage(
    e.target.files[0],
    function (img) {
      display.appendChild(img);
    },
    {
     maxWidth: 200,
     orientation: true
    } // Options
  )
}

We can now tidy up. The getElementById is duplicated, so we move that to a separate variable:

// document.getElementById('file-input').onclick = function (e) {
var fileInput = document.getElementById('file-input');
fileInput.onclick = function (e) {
  var display = document.querySelector("#display");
  display.innerHTML = "";
};
// document.getElementById('file-input').onchange = function (e) {
fileInput.onchange = function (e) {
  ...

The onclick and onchange events are historical and only allow one of each type on an element.
More modern techniques use addEventListener instead, which has no such limitations.

var fileInput = document.getElementById('file-input');
// fileInput.onclick = function (e) {
fileInput.addEventListener("click", function (e) {
  var display = document.querySelector("#display");
  display.innerHTML = "";
// };
});
// fileInput.onchange = function (e) {
fileInput.addEventListener("change", function (e) {
  ...
// }
});

As we have multiple event handlers, it’s useful to group them all together. We can easily achieve that by naming the functions and moving those functions out of the event assignment.

function fileClickHandler(e) {
  var display = document.querySelector("#display");
  display.innerHTML = "";
}
function fileChangeHandler(e) {
  var display = document.querySelector("#display");
  loadImage(
    e.target.files[0],
    function (img) {
      display.appendChild(img);
    },
    {
     maxWidth: 200,
     orientation: true
    } // Options
  )
}

var fileInput = document.getElementById('file-input');
fileInput.addEventListener("click", fileClickHandler);
fileInput.addEventListener("change", fileChangeHandler);

And lastly, the fileChangeHandler function is doing too much work. It’s job should only be to get information from the event handler and pass it on to where it’s needed.

function fileChangeHandler(e) {
  var display = document.querySelector("#display");
  var filename = e.target.files[0];
  showImage(filename, display);
}

So we can move the rest of the code into the showImage function:

function showImage(filename, container) {
  loadImage(
    filename,
    function (img) {
      container.appendChild(img);
    },
    {
     maxWidth: 200,
     orientation: true
    } // Options
  );
}

That options comment isn’t being of much use either. Sure, it’s telling us that those are options, so let’s use an options variable to hold them.

function showImage(filename, container) {
  var options = {
     maxWidth: 200,
     orientation: true
  };
  loadImage(
    filename,
    function (img) {
      container.appendChild(img);
    },
    options
  );
}

If we give that image function a name, we can move it out and simplify things quite nicely too, giving us a very simple loadImage call at the end of the function:

function showImage(filename, container) {
  function callback(img) {
    container.appendChild(img);
  }
  var options = {
     maxWidth: 200,
     orientation: true
  };
  loadImage(filename, callback, options);
}

The display variable is about the only duplication there now, but that’s not so easy to fix without committing egregious sins or turning it into a module.

Hrm - turn it into a module.

Start by wrapping the code in a named function:

function imageLoader() {
  ...
}

And we can now move the display variable out of there, passing it in to the imageLoader function instead.

function imageLoader(display) {
  ...
  function fileClickHandler(e) {
    // var display = document.querySelector("#display");
    display.innerHTML = "";
  }
  function fileChangeHandler(e) {
    // var display = document.querySelector("#display");
    ...
  }
  ...
}

var display = document.querySelector("#display");
imageLoader(display);

And we can even move the fileInput out of there too.

// function imageLoader(display) {
function imageLoader(fileInput, display) {
  ...
  // var fileInput = document.getElementById('file-input');
...
}

var fileInput = document.getElementById('file-input');
var display = document.querySelector("#display");
imageLoader(fileInput, display);

And we now have a meaningful story for the imageLoader. It attaches to the specified fileInput, and show whatever you get from there in the display area.

The final code is:

function imageLoader(fileInput, display) {
  function showImage(filename, container) {
    function callback(img) {
      container.appendChild(img);
    }
    var options = {
      maxWidth: 200,
      orientation: true
    };
    loadImage(filename, callback, options);
  }
  function fileClickHandler(e) {
    display.innerHTML = "";
  }
  function fileChangeHandler(e) {
    var filename = e.target.files[0];
    showImage(filename, display);
  }

  fileInput.addEventListener("click", fileClickHandler);
  fileInput.addEventListener("change", fileChangeHandler);
};

var fileInput = document.getElementById('file-input');
var display = document.querySelector("#display");
imageLoader(fileInput, display);