AJAX file upload with progress bar.
Full tutorial and explanation on Code Boxx.
| <div id="up-wrap"> | |
| <div id="upload"></div> | |
| <h1>UPLOAD PROGRESS BAR</h1> | |
| <!-- (A) PROGRESS BAR --> | |
| <div id="up-progress"> | |
| <div id="up-bar"></div> | |
| <div id="up-percent">0%</div> | |
| </div> | |
| <div id="up-demo">* Demo only, will not actually upload.</div> | |
| <!-- (B) FILE PICKER --> | |
| <input type="file" id="up-file" disabled/> | |
| <label for="up-file" id="up-label"> | |
| Select File | |
| </label> | |
| <!-- (X) VISIT CODE-BOXX --> | |
| <div id="code-boxx"> | |
| Visit | |
| <a href="https://code-boxx.com/ajax-upload-progress-bar/" | |
| target="_blank"> | |
| Code Boxx | |
| </a> for more details. | |
| </div> | |
| </div> |
| var uprog = { | |
| // (A) INIT | |
| hBar : null, // html progress bar | |
| hPercent : null, // html upload percentage | |
| hFile : null, // html file picker | |
| init : () => { | |
| // (A1) GET HTML ELEMENTS | |
| uprog.hBar = document.getElementById("up-bar"); | |
| uprog.hPercent = document.getElementById("up-percent"); | |
| uprog.hFile = document.getElementById("up-file"); | |
| // (A2) ATTACH AJAX UPLOAD + ENABLE UPLOAD | |
| uprog.hFile.onchange = uprog.upload; | |
| uprog.hFile.disabled = false; | |
| }, | |
| // (B) HELPER - UPDATE PROGRESS BAR | |
| update : (percent) => { | |
| percent = percent + "%"; | |
| uprog.hBar.style.width = percent; | |
| uprog.hPercent.innerHTML = percent; | |
| if (percent == "100%") { uprog.hFile.disabled = false; } | |
| }, | |
| // (C) PROCESS UPLOAD | |
| upload : async () => { | |
| // (C1) GET FILE + UPDATE HTML INTERFACE | |
| let file = uprog.hFile.files[0]; | |
| uprog.hFile.disabled = true; // disable upload button | |
| uprog.hFile.value = ""; // reset file picker | |
| // DUMMY UPLOAD DEMO | |
| await new Promise(e=>{setTimeout(e,500)}); | |
| uprog.update(25); | |
| await new Promise(e=>{setTimeout(e,500)}); | |
| uprog.update(50); | |
| await new Promise(e=>{setTimeout(e,500)}); | |
| uprog.update(75); | |
| await new Promise(e=>{setTimeout(e,500)}); | |
| uprog.update(100); | |
| /* THIS SHOULD BE THE ACTUAL AJAX UPLOAD | |
| // (C2) AJAX UPLOAD | |
| let xhr = new XMLHttpRequest(), | |
| data = new FormData(); | |
| data.append("upfile", file); | |
| xhr.open("POST", "upload.php"); | |
| // (C3) UPLOAD PROGRESS | |
| let percent = 0, width = 0; | |
| xhr.upload.onloadstart = (evt) => { uprog.update(0); }; | |
| xhr.upload.onloadend = (evt) => { uprog.update(100); }; | |
| xhr.upload.onprogress = (evt) => { | |
| percent = Math.ceil((evt.loaded / evt.total) * 100); | |
| uprog.update(percent); | |
| }; | |
| // (C4) ON LOAD & ERRORS | |
| xhr.onload = function () { | |
| if (this.response!= "OK" || this.status!=200) { | |
| // @TODO - DO SOMETHING ON ERROR | |
| // alert("ERROR!"); | |
| // reset form? | |
| console.log(this); | |
| console.log(this.response); | |
| console.log(this.status); | |
| } else { | |
| uprog.update(100); | |
| // @TODO - DO SOMETHING ON COMPLETE | |
| } | |
| }; | |
| // xhr.onerror = () => { DO SOMETHING }; | |
| // (C5) GO! | |
| xhr.send(data);*/ | |
| } | |
| }; | |
| window.addEventListener("load", uprog.init); |
| /* (A) WRAPPER */ | |
| #up-wrap, #up-wrap * { | |
| font-family: arial, sans-serif; | |
| box-sizing: border-box; | |
| } | |
| #up-wrap { | |
| width: 500px; | |
| padding: 20px; | |
| border-radius: 20px; | |
| background: rgba(255, 255, 255, 0.4); | |
| } | |
| /* (B) PROGRESS BAR */ | |
| #up-progress, #up-bar, #up-percent { height: 30px; } | |
| #up-progress { | |
| position: relative; | |
| background: #fff; | |
| } | |
| #up-bar { | |
| background: #d3e3ff; | |
| width: 0; | |
| transition: width 0.5s; | |
| } | |
| #up-percent { | |
| position: absolute; top: 0; left: 0; | |
| width: 100%; display: flex; | |
| align-items: center; justify-content: center; | |
| } | |
| /* (C) FILE PICKER */ | |
| #up-file { display: none; } | |
| #up-label { | |
| display: inline-block; | |
| margin-top: 20px; | |
| padding: 10px 20px; | |
| color: #fff; | |
| border: 1px solid #dfdfdf; | |
| background: #296cd0; | |
| cursor: pointer; | |
| } | |
| #up-file:disabled ~ #up-label { background: #b1b1b1; } | |
| /* (X) DOES NOT MATTER */ | |
| /* PAGE & BODY */ | |
| body { | |
| display: flex; | |
| align-items: center; justify-content: center; | |
| min-height: 100vh; | |
| background-image: url(https://images.unsplash.com/photo-1584968183745-e4c64b7df994?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTY0MjU3NTAyMQ&ixlib=rb-1.2.1&q=85); | |
| background-repeat: no-repeat; | |
| background-position: center; | |
| background-size: cover; | |
| } | |
| /* SVG */ | |
| #upload { | |
| width: 100%; height:100px; | |
| background-image: url('data:image/svg+xml;utf8,<svg viewBox="0 0 640 512" width="100" xmlns="http://www.w3.org/2000/svg"><path d="M537.6 226.6c4.1-10.7 6.4-22.4 6.4-34.6 0-53-43-96-96-96-19.7 0-38.1 6-53.3 16.2C367 64.2 315.3 32 256 32c-88.4 0-160 71.6-160 160 0 2.7.1 5.4.2 8.1C40.2 219.8 0 273.2 0 336c0 79.5 64.5 144 144 144h368c70.7 0 128-57.3 128-128 0-61.9-44-113.6-102.4-125.4zM393.4 288H328v112c0 8.8-7.2 16-16 16h-48c-8.8 0-16-7.2-16-16V288h-65.4c-14.3 0-21.4-17.2-11.3-27.3l105.4-105.4c6.2-6.2 16.4-6.2 22.6 0l105.4 105.4c10.1 10.1 2.9 27.3-11.3 27.3z" /></svg>'); | |
| background-repeat: no-repeat; | |
| background-position: center; | |
| } | |
| /* DEMO */ | |
| #up-wrap { text-align: center; } | |
| #up-wrap h1 { margin: 0 0 40px 0; } | |
| #up-demo { margin-top: 10px; } | |
| /* FOOTER */ | |
| #code-boxx { | |
| font-weight: 600; | |
| margin-top: 50px; | |
| } | |
| #code-boxx a { | |
| display: inline-block; | |
| padding: 5px; | |
| text-decoration: none; | |
| background: #b90a0a; | |
| color: #fff; | |
| } |