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; | |
} |