Search code examples
javascriptjquerycssdatatablesprogress-bar

How to create progress bar in datatables?


I am currently working in datatables with a lot of data (5000). To be able to load data with progress, I added a progress bar that states how much data has been loaded in each unit of time. But the code below is not working anymore.

let handleProgressBar = (id, value, total) => {
    let percent = Math.round((value / total) * 10000) / 100;
    $(id + " > div").html(percent + "%");
    $(id + " > div").css('width', percent + "%");
}

let table = $('#data').DataTable();

fetch('https://jsonplaceholder.typicode.com/photos')
.then((res) => res.json())
.then((res) => {
  res.forEach(async(data, index)=>{
    table.row.add([
      data.id,
      data.albumId,
      data.title,
      data.url
    ]);
    handleProgressBar('#progress-bar', index+1, res.length);
    await new Promise(r => setTimeout(r, 1)); // sleep 1 ms
  });
  table.draw();
});
.progress-bar-striped {
    overflow: hidden;
    height: 20px;
    margin-bottom: 20px;
    background-color: #f5f5f5;
    border-radius: 4px;
    -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
    -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
}

.progress-bar-striped>div {
    background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
    background-size: 40px 40px;
    float: left;
    width: 0%;
    height: 100%;
    font-size: 12px;
    line-height: 20px;
    color: #000000;
    font-weight: bold;
    text-align: center;
    -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
    -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
    box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
    /*-webkit-transition: width 3s ease;
    -moz-transition: width 3s ease;
    -o-transition: width 3s ease;
    transition: width 3s ease;*/
    animation: progress-bar-stripes 2s linear infinite;
    background-color: #288ade;
}

.progress-bar-striped p {
    margin: 0;
}

@keyframes progress-bar-stripes {
    0% {
        background-position: 40px 0;
    }
    100% {
        background-position: 0 0;
    }
}
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>

<div id="progress-bar" class="progress-bar-striped">
    <div style="width: 0%;">
        <p>0%</p>
    </div>
</div>

<table id="data" class="table display table-stripped">
    <thead>
        <tr>
            <th>ID</th>
            <th>Album ID</th>
            <th>Title</th>
            <th>URL Photo</th>
        </tr>
    </thead>
    <tbody></tbody>
</table>

The table has been loaded successfully but the progress bar shows 100% instead of should increment from 0% to 100%. I wonder about it works (but not perfectly) if I don't use datatable as shown in the code below.

let handleProgressBar = (id, value, total) => {
    let percent = Math.round((value / total) * 10000) / 100;
    $(id + " > div").html(percent + "%");
    $(id + " > div").css('width', percent + "%");
}

(async() =>{
  let n = 5000;
  handleProgressBar('#progress-bar', 0, n);
  for(let i = 1; i <= n; i++) {
    handleProgressBar('#progress-bar', i, n);
    await new Promise(r => setTimeout(r, 1)); // sleep 1 ms
  }
})();
.progress-bar-striped {
    overflow: hidden;
    height: 20px;
    margin-bottom: 20px;
    background-color: #f5f5f5;
    border-radius: 4px;
    -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
    -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
}

.progress-bar-striped>div {
    background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
    background-size: 40px 40px;
    float: left;
    width: 0%;
    height: 100%;
    font-size: 12px;
    line-height: 20px;
    color: #000000;
    font-weight: bold;
    text-align: center;
    -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
    -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
    box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
    /*-webkit-transition: width 3s ease;
    -moz-transition: width 3s ease;
    -o-transition: width 3s ease;
    transition: width 3s ease;*/
    animation: progress-bar-stripes 2s linear infinite;
    background-color: #288ade;
}

.progress-bar-striped p {
    margin: 0;
}

@keyframes progress-bar-stripes {
    0% {
        background-position: 40px 0;
    }
    100% {
        background-position: 0 0;
    }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="progress-bar" class="progress-bar-striped">
    <div style="width: 0%;">
        <p>0%</p>
    </div>
</div>

I have no idea where the mistake is. Can anyone provide me with the perfect way to handle the progress bar for datatable with a lot of data? Thanks before.


Solution

  • I have found the solution. The mistake is I put the async word inside res.forEach. When I put it after fetch.then and use for loop instead of forEach, the behavior of function execution changed and can be done successfully. The loadNumber variable can be used for determining how much data which will draw in datatables per unit of time.

    let handleProgressBar = (id, value, total) => {
        let percent = Math.round((value / total) * 10000) / 100;
        $(id + " > div").html(percent + "%");
        $(id + " > div").css('width', percent + "%");
    }
    
    let table = $('#data').DataTable({
      dom: 'ilpftr'
    });
    
    fetch('https://jsonplaceholder.typicode.com/photos')
    .then((res) => res.json())
    .then(async(res) => {
      let loadNumber = 50;
      for(let i = 0; i < res.length; i++) {
        table.row.add([
          res[i].id,
          res[i].albumId,
          res[i].title,
          res[i].url
        ]);
        if (i % loadNumber == 0) {
          table.draw();
          handleProgressBar('#progress-bar', i+1, res.length);
          await new Promise(r => setTimeout(r, 1)); // sleep 1 ms
        }
      }
      table.draw();
      handleProgressBar('#progress-bar', res.length, res.length);
    });
    .progress-bar-striped {
        overflow: hidden;
        height: 20px;
        margin-bottom: 20px;
        background-color: #f5f5f5;
        border-radius: 4px;
        -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
        -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
        box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
    }
    
    .progress-bar-striped>div {
        background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
        background-size: 40px 40px;
        float: left;
        width: 0%;
        height: 100%;
        font-size: 12px;
        line-height: 20px;
        color: #000000;
        font-weight: bold;
        text-align: center;
        -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
        -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
        box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
        /*-webkit-transition: width 3s ease;
        -moz-transition: width 3s ease;
        -o-transition: width 3s ease;
        transition: width 3s ease;*/
        animation: progress-bar-stripes 2s linear infinite;
        background-color: #288ade;
    }
    
    .progress-bar-striped p {
        margin: 0;
    }
    
    @keyframes progress-bar-stripes {
        0% {
            background-position: 40px 0;
        }
        100% {
            background-position: 0 0;
        }
    }
    <link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet"/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
    
    <div id="progress-bar" class="progress-bar-striped">
        <div style="width: 0%;">
            <p>0%</p>
        </div>
    </div>
    
    <table id="data" class="table display table-stripped">
        <thead>
            <tr>
                <th>ID</th>
                <th>Album ID</th>
                <th>Title</th>
                <th>URL Photo</th>
            </tr>
        </thead>
        <tbody></tbody>
    </table>