HTML5 progress bar with Javascript Logic

I want to have a hyperlink file download in an html5 document. I want to link the tag to some vanilla javascript, by ajax and XMLHttpRequest. I want to use the javascript to examine the file download as it leaves the browser and goes to the download client device’s directory. I want to be able to display percentage completed, bytes, kilobytes or Megabytes completed, changing and displaying at the instant the file download progresses, irrespective of any length setting(s) on the progress bar.

I have not been able to debug my own javascript code, or any volunteer code from the internet, particularly code that does NOT use PHP or JQuery.

Is it possible to achieve this using only client side Javascript or CSS or HTML5?

Can someone please respond with some vanilla javascript that runs correctly, in relation to my code fragment included down here, kindly, please?

<a id="fileLink" href="superman.png"> <!--  download="superman.png" -->
Download Superman Logo
</a>.
<progress id="progress" value="0"></progress>
<script>
</script>

What you are wanting to do is not supported by JavaScript, as there are too many security issues that can be exploited.

I am ready for Cunningham’s Law to occur on this, but I think I’m pretty safe.

1 Like

Do you want to do something like the example here?

If so, you would not use an <a> element with href attribute.

I think the file needs to be quite large otherwise the load ends before a progress event fires. I guess that depends on broadband speed.

1 Like

Or using fetch(), you can monitor the progress by “manually” reading the response stream, and then creating an object URL from the collected chunks:

<a href="dummy.mp4" id="download">download</a>
<a hidden id="save">save</a>
<progress id="progress" value="0"></progress>
const link = document.getElementById('download')
const save = document.getElementById('save')
const progress = document.getElementById('progress')

class ReaderIterator {
  constructor (reader) {
    this.reader = reader
  }

  [Symbol.asyncIterator] () {
    return this
  }

  next () {
    return this.reader.read()
  }
}

link.addEventListener('click', async event => {
  event.preventDefault()
  link.hidden = true

  const response = await fetch(link.href)
  const reader = response.body.getReader()
  const iterator = new ReaderIterator(reader)
  const contentType = response.headers.get('Content-Type')
  const contentLength = response.headers.get('Content-Length')
  const chunks = []

  progress.max = contentLength

  for await (const chunk of iterator) {
    chunks.push(chunk)
    progress.value += chunk.length
  }

  save.href = URL.createObjectURL(new Blob(chunks, { type: contentType }))
  save.download = link.href.split('/').pop()
  save.hidden = false
})

As @Archibald noted though that only makes sense for very large files – images will probably get downloaded in one single chunk or two.

Copying all of this code into the html of an appropriately setup html5 document, and the javascript into a script tag area, I find that this code does not run while my 200 Mb file downloads. I certainly get
no action on my progress bar. I am using 64 bit Firefox version 90.0.2 on 64 bit Windows 10.
Could you please review this code, perhaps with this web browser, because it in fact doesn’t give me
the results that I have hoped for.

?

Works for me of FF too…

Peek 2021-07-26 12-35

The only browser that would require major code adjustments would be IE, which doesn’t support fetch() or basically anything added to the language or DOM API since 2015. Note though that for AJAX to work, the requested file must be served from the same origin (or CORS must be enabled); and it won’t work if you just open your HTML file from the file system.

Other than that, are you getting any errors in the console, and does the requested file show up in the network panel of the browser dev tools?

A progress bar works for me on this free webspace:
http://flexi.epizy.com/progress.html

That’s based on the example from MDN (see post #2).