skip to Main Content

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


  1. 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, the target property refers to the button.

    For a button that encloses other elements use event.target.closest('button') to get to the actual button element.

    Login or Signup to reply.
  2. Here’s just a simple example on how you can get it working with onclick attribute…

    function downloadMe ( element )
    {
      const container = element.parentNode;
      const progress = container.querySelector('.progress-bar');
      const download = element.dataset.download;
      
      // From here on you can manage almost everything you need to do.
      console.log
      ({
          'Container ID:': container.id,
          'Progress Bar:': progress.outerHTML,
          'Download URL:': download,
      });
    };
    <!-- Fix the HTML below to fit your needs -->
    <div id="container-1">
      <a  href="javascript:;"
          onclick="downloadMe(this)"
          data-download="some-url.1.link"
      > Download #1 </a>
      <div class="progress-bar"></div>
    </div>
    <div id="container-2">
      <a  href="javascript:;"
          onclick="downloadMe(this)"
          data-download="some-url.2.link"
      > Download #2 </a>
      <div class="progress-bar"></div>
    </div>
    <div id="container-3">
      <a  href="javascript:;"
          onclick="downloadMe(this)"
          data-download="some-url.3.link"
      > Download #3 </a>
      <div class="progress-bar"></div>
    </div>

    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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search