I programmed a a download progress bar. On click of the element it starts the download and shows the download progress. Sadly I cannot get it to work for multiple buttons and I am at a loss for options.
In detail what i am looking for: on click it gets the calling elements ID and the file supposed to be downloaded when pressing button {num}. Then use the id for the eventhandler and download the file.
First post on here so tell me what i should do differently.
Thanks in advance.
const fileToDownload = 'img/jdk-22_windows-x64_bin.exe';
const startDownloadElem = document.getElementById('startDownload');
const downloadProgressElem = document.querySelector(
'.download-progress-bar__progress'
);
console.log('Initially ' + (window.navigator.onLine ? 'on' : 'off') + 'line');
window.addEventListener('online', () => console.log('Became online'));
window.addEventListener('offline', () => console.log('Became offline'));
//document.getElementById('statusCheck').addEventListener('click', () => console.log('window.navigator.onLine is ' + window.navigator.onLine));
startDownloadElem.addEventListener('click', () => {
// downloadProgressElem.style.background = 'linear-gradient(to right, rgba(255, 0, 0, 0), rgb(255, 0, 0))';
console.log('Download Started');
startDownloadElem.setAttribute('disabled', 'true');
const dataChunks = [];
fetch(`/${fileToDownload}`)
.then(response => {
const reader = response.body.getReader();
const totalSize = Number(
response.headers.get('content-length')
);
let totalSizeDownloaded = 0;
downloadProgressElem.classList.remove('error');
function readData() {
return reader.read().then(result => {
if (result.value) {
dataChunks.push(result.value);
totalSizeDownloaded += result.value.length;
const percentage = Math.floor(
(totalSizeDownloaded / totalSize) * 100
);
console.log(
`${totalSizeDownloaded}/${totalSize} (${percentage}%)`
);
downloadProgressElem.textContent = `${percentage}%`;
downloadProgressElem.style.width = `${percentage}%`;
}
if (!result.done) {
return readData();
}
});
}
return readData();
})
.then(() => {
console.log('Download finished');
const downloadAnchor = document.createElement('a');
const blob = new Blob(dataChunks);
downloadAnchor.href = URL.createObjectURL(blob);
downloadAnchor.download = fileToDownload;
document.body.appendChild(downloadAnchor);
downloadAnchor.click();
document.body.removeChild(downloadAnchor);
})
.catch( () => {
downloadProgressElem.textContent = 'Download error';
downloadProgressElem.classList.add('error');
})
.finally(() => {
startDownloadElem.removeAttribute('disabled');
})
})
html {
height: 100%;
}
body {
height: 100%;
}
#startDownload {
background: #c50408;
color: honeydew;
padding: 10px;
}
#startDownload:disabled {
background-color: rgb(39, 92, 74);
}
.button-and-progress-div {
display: flex;
flex-flow: nowrap column;
align-items: center;
justify-content: center;
height: 100%;
}
.download-progress-bar__container {
margin: 20px 0;
width: 400px;
height: 40px;
border-radius: 10px;
}
.download-progress-bar__progress {
background: linear-gradient(to right, rgba(255, 0, 0, 0), rgb(255, 0, 0));
border-radius: 10px;
color: honeydew;
display: flex;
align-items: center;
justify-content: center;
width: 0;
height: 100%;
}
.download-progress-bar__progress.error {
background: linear-gradient(to right, rgba(138, 0, 226, 0), rgb(138, 0, 226, 1));
}
<html class="no-js" lang="">
<head>
<script src="js/app.js" defer></script>
</head>
<body>
<div class="button-and-progress-div">
<a class="download-start-button" id="startDownload" data-file-to-download="img/jdk-22_windows-x64_bin.exe">Download</a>
<div class="download-progress-bar__container" id="progbardiv">
<div class="download-progress-bar__progress"></div>
</div>
</div>
</body>
</html>
2
Answers
Use the click event listener argument
The handler for the download button is passed an
event
object as its argument when the button is clicked.The
event.target
property is a reference to the element the user clicked. For a plain button without images or styled content between the button tags, thetarget
property refers to the button.For a button that encloses other elements use
event.target.closest('button')
to get to the actual button element.Here’s just a simple example on how you can get it working with
onclick
attribute…Note that there’s a need to customize the HTML/CSS stuff to fit the needs. This is just a simple example to show a way, from many, to resolve the problem.