1

Info: I want to upload multiple file using tus-js-client. I am facing some issue when i try to upload multiple files.

Issues:

  • If i try to upload multiple files The progress bar is fluctuating because index of chunks are not properly so that's why the progress bar is fluctuating.

  • I want each file upload next file start after first file complete.

const fileInput = document.querySelector('#js-file-input')
    const dataDiv = document.querySelector('#data-pre');
    const toggleBtn = document.querySelector('#toggle-btn')
    const progressBar = document.querySelector('.progress-bar')
    const textProgress = document.querySelector('#js-upload-text-progress')
    const uploadList = document.querySelector('#upload-list')

    function reset() {
      progressBar.style.width = `${0}%`
      textProgress.textContent = ""
    }
    /**
   * Turn a byte number into a human readable format.
   * Taken from https://stackoverflow.com/a/18650828
   */
    function formatBytes(bytes, decimals = 2) {
      if (bytes === 0) return '0 Bytes'

      const k = 1024
      const dm = decimals < 0 ? 0 : decimals
      const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
      const i = Math.floor(Math.log(bytes) / Math.log(k))
      return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
    }

    fileInput.addEventListener('change', (e) => {
      const files = e.target.files;
      let convertedFiles = [];

      Object.keys(files).forEach(k => {
        convertedFiles = [
          ...convertedFiles,
          { id: URL.createObjectURL(files[k]), file: files[k] }
        ];
      });

      convertedFiles.map(i => {
        const file = i.file;
        const chunkSize = parseInt(5242880, 10)

        let upload = new tus.Upload(file, {
          endpoint: "https://tusd.tusdemo.net/files/",
          // endpoint: "http://localhost:8000/tus/upload/",
          chunkSize,
          retryDelays: [0, 1000, 3000, 5000],
          metadata: {
            filename: file.name,
            filetype: file.type
          },
          onError: function (error) {
            console.log("Failed because: " + error);
          },
          onProgress: function (bytesUploaded, bytesTotal) {
            const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2)
            progressBar.style.width = `${percentage}%`
            textProgress.textContent = `Uploaded ${formatBytes(bytesUploaded)} of ${formatBytes(bytesTotal)} (${percentage})`
            console.log(bytesUploaded, bytesTotal, percentage + "%");
          },
          onSuccess: function () {
            const anchor = document.createElement('a')
            anchor.textContent = `Download ${upload.file.name} (${upload.file.size} bytes)`
            anchor.href = upload.url
            anchor.className = 'btn btn-success'
            uploadList.appendChild(anchor)
            console.log("Download %s from %s", upload.file.name, upload.url);

            reset()
          }
        });

        toggleBtn.addEventListener('click', (e) => {
          upload.start()
        });

        dataDiv.innerHTML +=
          `
          <div class="file-data" key=${i.file.id}>
            <img alt="what" src=${i.id} width="150" />
            <div>name: ${i.file.name}</div>
            <div>type: ${i.file.type}</div>
            <div>size: ${i.file.size}</div>
          </div>
       `
      });
    });
 <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
    integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/tus.min.js"></script>
<div class="upload-card">
      <div class="row">
        <div class="col-md-12">

          <div id="input-section">
            <div class="heading">Select a file you want to upload:</div>
            <input type="file" id="js-file-input" accept="image/*, video/*" multiple>
            <!-- <input type="file" id="input-file" accept="image/*" multiple> -->

          </div>

          <div id="progress-section">
            <div class="heading" id="heading"></div>
            <div class="d-flex">
              <div class="flex-grow-1">
                <div class="progress">
                  <div class="progress-bar progress-bar-striped bg-success" role="progressbar"></div>
                </div>
                <div class="upload-text-progress" id="js-upload-text-progress"></div>
              </div>
              <div class="js-action-btn">
                <button class="btn stop" id="toggle-btn">start</button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <hr>
    <h3>Uploads</h3>
    <p>Succesful uploads will be listed here. Try one!</p>
    <p id="upload-list"></p>
    <br>
    <hr>
    <div id="data-pre"></div>

1 Answer 1

1

I've found a solution.

It's works for me, you need only change your Javascript code and remove progress bar form HTML. Then you can edit css to make it better. ;)

Edit I've added a demo.

  const fileInput = document.querySelector('#js-file-input')
  const dataDiv = document.querySelector('#data-pre');
  const toggleBtn = document.querySelector('#toggle-btn')
  const uploadList = document.querySelector('#upload-list')


  function reset() {
    convertedFiles.map((i, key) => {
      $('.progress-bar_' + key).css('width', '0%');
      $('#js-upload-text-progress_' + key).html('');
    })
  }
  /**
  * Turn a byte number into a human readable format.
  * Taken from https://stackoverflow.com/a/18650828
  */

  function formatBytes(bytes, decimals = 2) {
    if (bytes === 0) return '0 Bytes'

    const k = 1024
    const dm = decimals < 0 ? 0 : decimals
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
    const i = Math.floor(Math.log(bytes) / Math.log(k))
    return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
  }

  let convertedFiles = [];
  fileInput.addEventListener('change', (e) => {
    dataDiv.innerHTML = '';
    const files = e.target.files;
    Object.keys(files).forEach(k => {
      convertedFiles = [
      ...convertedFiles,
      { id: URL.createObjectURL(files[k]), file: files[k]}
      ];
    });


    convertedFiles.map((i, key) => {
      const file = i.file;
      key ++
      const chunkSize = parseInt(5242880, 10)

      dataDiv.innerHTML +=
      `
      <div class="file-data" key=${key}>
        <img alt="what" src=${i.id} width="150" />
        <div>name: ${i.file.name}</div>
        <div>type: ${i.file.type}</div>
        <div>size: ${i.file.size}</div>
        <div class="flex-grow-1">
          <div class="progress pr_${key}">
            <div class="progress-bar_${key} progress-bar-striped bg-success" role="progressbar"></div>
          </div>
          <div class="upload-text-progress" id="js-upload-text-progress_${key}"></div>
        </div>
      </div>
      `

      let upload = new tus.Upload(file, {
        endpoint   : 'https://tusd.tusdemo.net/files/',
        // endpoint: "http://localhost:8000/tus/upload/",
        chunkSize,
        retryDelays: [0, 1000, 3000, 5000],
        metadata: {
          filename: file.name,
          filetype: file.type
        },
        onError: function (error) {
          console.log("Failed because: " + error);
        },
        onProgress: function (bytesUploaded, bytesTotal) {
          const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2)
          $('.progress-bar_' + key).css('width', percentage + '%');
          $('#js-upload-text-progress_' + key).html(`Uploaded ${formatBytes(bytesUploaded)} of ${formatBytes(bytesTotal)} (${percentage})`);
        },
        onSuccess: function () {
          const anchor = document.createElement('a')
          anchor.textContent = `Download ${upload.file.name} (${upload.file.size} bytes)`
          anchor.href = upload.url
          anchor.className = 'btn btn-success'
          uploadList.appendChild(anchor)
          console.log("Download %s from %s", upload.file.name, upload.url);
        }
      });

      toggleBtn.addEventListener('click', (e) => {
        reset();
        upload.start()
      });

    });
  });
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/tus.min.js"></script>
<div class="upload-card">
  <div class="row">
    <div class="col-md-12">

      <div id="input-section">
        <div class="heading">Select a file you want to upload:</div>
        <input type="file" id="js-file-input" accept="image/*, video/*" multiple>
        <!-- <input type="file" id="input-file" accept="image/*" multiple> -->

      </div>

      <div id="progress-section">
        <div class="heading" id="heading"></div>
        <div class="d-flex">
          <div class="js-action-btn">
            <button class="btn stop" id="toggle-btn">start</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
<hr>
<h3>Uploads</h3>
<p>Succesful uploads will be listed here. Try one!</p>
<p id="upload-list"></p>
<br>
<hr>
<div id="data-pre"></div>

Hope it helps

Sign up to request clarification or add additional context in comments.

2 Comments

Please comment your code and write some explanations so that OP and future readers can see what you have changed, where and why
Yes sorry i'm new here... I've added reset function, because before I've lost them. But differently by example I moved on upload function, so progress bar will be clear everytime.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.