Using <input type="file"> to display uploaded files with iframe

971 views Asked by At

I want to use a file input so that a user could upload a folder containing their site files, then the program finds the index file in the folder then displays it in the iframe.

I attepted to do this myself (shown below) using a folder containing a simple html and css file, but index.html would never load.

<!doctype html>
<html>
    <body>
        <input type="file" id="fileSelect" webkitdirectory>

        <iframe id="iframeView" height="400" width="600"></iframe>
        
        <script>
            //Instantiate to reduce visual complexity
            const frameElement = document.getElementById("iframeView");
            const fileElement = document.getElementById("fileSelect");
            
            //Call loadURL when a folder is selected
            fileElement.addEventListener("change", loadURL);
            
            //Get index.html file from folder and make it the iframe src
            function loadURL() {
                frameElement.src = fileElement.files["index.html"];
            }
        </script>
    </body>
</html>
2

There are 2 answers

3
XMehdi01 On BEST ANSWER

Use Array#find to find the index.html file in the selected folder. And use The FileReader API to read its content.

const frameElement = document.getElementById("iframeView");
const fileElement = document.getElementById("fileSelect");
fileElement.addEventListener("change", loadURL);

function loadURL() {
  const files = Array.from(fileElement.files);
  const indexFile = files.find((file) => file.name === "index.html");
  if (indexFile) {
    const reader = new FileReader();
    reader.onload = function(e) {
      frameElement.src = e.target.result;
    };
    reader.readAsDataURL(indexFile);
  }
}
<input type="file" id="fileSelect" webkitdirectory />
<iframe id="iframeView" height="400" width="600"></iframe>

2
Jay Dadhaniya On

The solution with readAsDataURL all worked fine for small files, but when the size increased, we started to see issues.

Issues:

  1. The URL max length is different across multiple browsers, so this would be one big restriction in some browsers the URL max length and in some not but not showing it.
  2. The readAsDataURL converts the buffer to a base64 string and keeps it in memory. When you are not using it, the memory gets cleared up by the garbage collector.

As a solution for all these issues, I used the readAsArrayBuffer and created an object URL.

function createfileURL(file){
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.readAsArrayBuffer(file);

        reader.onload = function (e) {
            const buffer = e.target.result;
            const fileBlob = new Blob([new Uint8Array(buffer)], { type: file.type})
            return resolve(window.URL.createObjectURL(fileBlob));
        };
    })
}