0
\$\begingroup\$

I would like to know how to make this faster. It's okay for 100 rows but 1k, 10k, 100k is different.

let array = {
  "PageOption": {
    "rowperpage": "10",
    "rowtotal": "235",
    "currentPage": "1",
    "divheight": "250"
  },
  "header": [
    {
      "visible": true,
      "label": "rownum",
      "fontweight": "normal",
      "footer": "Sum"
    },
    {
      "visible": true,
      "label": "subpkid",
      "fontweight": "normal",
      "footer": "Sum"
    },
    {
      "visible": true,
      "label": "destsubpkid",
      "fontweight": "normal",
      "footer": "Sum"
    },
    {
      "visible": true,
      "label": "jrlpkid",
      "fontweight": "normal",
      "footer": "max"
    },
    {
      "visible": true,
      "label": "jrltype",
      "fontweight": "normal",
      "footer": "Sum"
    },
    {
      "visible": true,
      "label": "invtype",
      "fontweight": "normal",
      "footer": "Sum"
    },
    {
      "visible": true,
      "label": "accountid",
      "fontweight": "normal",
      "footer": "Sum"
    },
    {
      "visible": true,
      "label": "expID",
      "fontweight": "normal",
      "footer": "Sum"
    },
    {
      "visible": true,
      "label": "invdate",
      "fontweight": "normal",
      "footer": "Sum"
    },
    {
      "visible": true,
      "label": "invno",
      "fontweight": "normal",
      "footer": "Sum"
    },
    {
      "visible": true,
      "label": "invdesc",
      "fontweight": "normal",
      "footer": "Sum"
    },
    {
      "visible": true,
      "label": "dtamt",
      "fontweight": "normal",
      "footer": "Sum"
    },
    {
      "visible": true,
      "label": "currate",
      "fontweight": "normal",
      "footer": "Sum"
    },
    {
      "visible": true,
      "label": "dtamtf",
      "fontweight": "normal",
      "footer": "Sum"
    },
    {
      "visible": true,
      "label": "isdebit",
      "fontweight": "normal",
      "footer": "Sum"
    },
    {
      "visible": true,
      "label": "cusid",
      "fontweight": "normal",
      "footer": "Sum"
    }
  ],
  "rows": [
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "20000",
      "jrltype": "MOD",
      "jrlpkid": "526",
      "subpkid": "190001011011003632",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20120608101100001"
    },
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "1003764",
      "jrltype": "OD",
      "jrlpkid": "895",
      "subpkid": "190001011011003633",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20101023101100273"
    },
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "1003764",
      "jrltype": "OD",
      "jrlpkid": "895",
      "subpkid": "190001011011003633",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20101023101100273"
    },
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "1003764",
      "jrltype": "OD",
      "jrlpkid": "895",
      "subpkid": "190001011011003633",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20101023101100273"
    },
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "1003764",
      "jrltype": "OD",
      "jrlpkid": "895",
      "subpkid": "190001011011003633",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20101023101100273"
    },
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "1003764",
      "jrltype": "OD",
      "jrlpkid": "895",
      "subpkid": "190001011011003633",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20101023101100273"
    },
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "1003764",
      "jrltype": "OD",
      "jrlpkid": "895",
      "subpkid": "190001011011003633",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20101023101100273"
    },
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "1003764",
      "jrltype": "OD",
      "jrlpkid": "895",
      "subpkid": "190001011011003633",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20101023101100273"
    },
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "1003764",
      "jrltype": "OD",
      "jrlpkid": "895",
      "subpkid": "190001011011003633",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20101023101100273"
    },
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "0",
      "jrltype": "KOD",
      "jrlpkid": "453",
      "subpkid": "190001011011003634",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20101202101100001"
    },
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "124000",
      "jrltype": "DON",
      "jrlpkid": "1562",
      "subpkid": "190001011011003635",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20130124101100002"
    },
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "319090.59",
      "jrltype": "HOD",
      "jrlpkid": "1562",
      "subpkid": "190001011011003636",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20101023101100050"
    },
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "0",
      "jrltype": "YOSH",
      "jrlpkid": "1562",
      "subpkid": "190001011011003637",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20101023101100270"
    },
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "0",
      "jrltype": "ZOD",
      "jrlpkid": "1562",
      "subpkid": "190001011011003638",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20101023101100265"
    },
    {
      "rownum": "1",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "0",
      "jrltype": "GOD",
      "jrlpkid": "1562",
      "subpkid": "190001011011003639",
      "isdebit": "1232131231231",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20101023101100263"
    },
    {
      "rownum": "2",
      "currate": "2",
      "invtype": "3",
      "invdesc": "BEGIN GOOD",
      "invdate": "1900/01/01",
      "destsubpkid": "0",
      "dtamt": "INS",
      "cusid": "2014/03/22 13:35:02",
      "dtamtf": "0",
      "jrltype": "GOD",
      "jrlpkid": "1562",
      "subpkid": "190001011011003640",
      "isdebit": "123213",
      "expid": "1900/01/01",
      "invno": "0",
      "accountid": "20101023101100051"
    }
  ]
};
let counter=0;
let cont = $('.cont');
 function header(array){
        let div = $("<div></div>");
        let extraheader = $('<div></div>').addClass('extraFixedHeader');
        $(cont).find('table').parent().before(div.clone().addClass('fixedheaderHolder'))
        $.each(array.header,function(key,value){
        let main = $(cont).find('table').find('thead').children('tr');
        let mainfooter = $(cont).find('table').find('tfoot').children('tr');
        
        var html = $("<th></th>");
        let styleClass=' ';
        let checkbox = $('<input type="checkbox" />').on('click',function(e){
          e.stopPropagation();
        });
        let span = $('<span></span>')
        let sorttrigger = $('<i></i>').addClass('fas fa-sort').addClass('sortTrigger text-secondary').attr('data-sorted','none');
        let icon = sorttrigger.clone();
        let label = $('<label></label>');
        let itemShow = label.clone();
        itemShow.off('click');
        itemShow.on('click',function(){          
          if(!$(this).find('input').is(':checked')){
          }
          let direction=$(this).find('span').attr('data-freeze-column');
          let colindex=$(this).parents('th').attr('data-column-index');
          let table = main.parents('table');

          let width = $(this).parents('table').find('tbody tr td[data-column-index="'+colindex+'"]').outerWidth()+6;
          let height = $(this).parents('table').find('tbody tr td').outerHeight();

          let headerheight = $(this).parents('th').outerHeight();
          
          switch(direction){
            case 'left':            
               table.find('tbody tr[data-row="true"]').each(function(){
                  $(this).find('td').eq(colindex).removeClass('freezeRight freezeLeft').addClass('freezeLeft').css({
                    'width':width,
                    'height':height
                  });
               });
             
              $(this).parents('th').removeClass('freezeRight freezeLeft').addClass('freezeLeft').css({
                'width':width,
              });

              break;
            case 'right':
              
              table.find('tbody tr[data-row="true"]').each(function(){
                console.log($(this).find('td').eq(colindex).outerHeight());
                  $(this).find('td').eq(colindex).removeClass('freezeRight freezeLeft').addClass('freezeRight').css({
                'width':width,
                  });
               });
              $(this).parents('th').removeClass('freezeRight freezeLeft').addClass('freezeRight');
              
              break;
            default:
             table.find('tbody tr[data-row="true"]').find('td:nth-child('+(+colindex+1)+')').removeClass('freezeRight freezeLeft');
              $(this).parents('th').removeClass('freezeRight freezeLeft');
              break;
          }

        })

        icon.click(function(){
          let sortdir = $(this).attr('data-sorted');
          var table = $(this).parents('table');
          var col = $(this).parents('th').attr('data-column-index');
          icon.closest('tr').find('.sortTrigger').attr('data-sorted','none');
          icon.closest('tr').find('.sortTrigger').addClass('fa-sort').removeClass('fa-sort-up fa-sort-down');         
          var rows = table.find('tbody tr[data-row="true"]').toArray().sort(comparer($(this).parents('th').index()))

          switch (sortdir){
            case 'none':
              $(this).attr('data-sorted','asc');
              $(this).removeClass('fa-sort').addClass('fa-sort-up');         
               this.asc = true;
              
              break;
            case 'asc':
              $(this).attr('data-sorted','desc');
              $(this).removeClass('fa-sort-up').addClass('fa-sort-down');

               this.asc = false;
              
              break;
             
            case 'desc':
             $(this).attr('data-sorted','none');
             this.asc = 'none';
              $(this).removeClass('fa-sort-down').addClass('fa-sort');
              break;
          }
          if($(cont).find('.rowOrder ').children().length > 0){
              return false;
          }
        
          if (!this.asc){
            rows = rows.reverse()
          }
          if(this.asc != 'none'){
          for (var i = 0; i < rows.length; i++){
            table.append(rows[i])
          }  
          }
          
        });
        let resizeable = div.clone().append(icon,span.clone().addClass('headerName').html(value.label)).addClass('resizeHeader');

        let dropdowntrigger = $('<i></i>').addClass('fas fa-bars headerdroptriger').attr({
          "data-toggle":"dropdown",
          "aria-haspopup":"true",
        });

        let dropdown = div.clone().addClass('dropdown-menu').css({
          'width':'100px',
        })
        let item = $('<a></a>').addClass('dropdown-item');
        // dropdown.append(item.clone().append(itemShow.clone(true).append(checkbox.clone(true),span.clone().text('To right').attr('data-freeze-column','right'))));
        // dropdown.append(item.clone().append(itemShow.clone(true).append(checkbox.clone(true),span.clone().text('To left').attr('data-freeze-column','left'))));
        // dropdown.append(item.clone().append(itemShow.clone(true).append(checkbox.clone(true),span.clone().text('None').attr('data-freeze-column','none'))));
        html.append(resizeable,div.clone().html('&nbsp;').addClass('resizeHandler')).attr('data-column-index',counter).attr({
          'data-height':html.outerHeight(),
          'data-width':html.outerWidth()
        }).hide();
        extraheader.append(div.clone().append(resizeable.clone(true).attr('data-column-index',counter)).addClass('fixedItem').css({
         
        })).attr('data-column-index',counter);
        switch(value.visible){
            case true:
                styleClass+='table-th-show ';
                break;
            case false:                
                styleClass+='table-th-hide ';
                break;
        }
        switch(value.fontweight.toLowerCase()){
            case 'lighter':
                styleClass+='table-font-weight-light ';
                break;
            case 'normal':                
                styleClass+='table-font-weight-normal ';
                break;
            case 'heavy':                
                styleClass+='table-font-weight-heavy ';
                break;
            case 'bold':                
                styleClass+='table-font-weight-bold ';
                break;                
        }
        switch(value.footer.toLowerCase()){
            case 'sum':
                styleClass+='table-footer-data-sum ';
                break;
            case 'avg':                
                styleClass+='table-footer-data-avg ';
                break;
            case 'min':                
                styleClass+='table-footer-data-min ';
                break;
            case 'max':                
                styleClass+='table-footer-data-max ';
                break;                
            default:
              styleClass+=''
              break;
        }

        html.addClass(styleClass);      

        main.append(html);
        
        mainfooter.append(html.clone().text(''));

        counter++;

    });
      $(cont).find('.fixedheaderHolder').append(div.clone().addClass('fixedrow').append(extraheader.children()));
    };
    header(array);
function body(array){
         let i=0;
        $.each(array.rows, function(key,value){
            let main = $(cont).find('table').find('tbody');
            let row=$('<tr></tr>').attr({
              'data-row':'true',
              'role':'row',
            });
            let td='';
            if(i==0){
             row.addClass('RowSelected');
            }
            let k = 0;
            let currentrow=array.rows[i];
            let countercolindex = 0;
            $.each(currentrow,function(key,value){

                let headerProp=array.header[k].label.toLowerCase();            

                td=$("<td></td>").attr('data-column-index',countercolindex);

                td.text(currentrow[headerProp]);
                td.on('click',function(){
                  if(main.find('.RowSelected').length > 0){
                      main.find('.RowSelected').removeClass('RowSelected');
                      main.find($(this)).closest('tr').addClass('RowSelected');
                  }
                  else{
                      main.find($(this)).closest('tr').addClass('RowSelected');
                  }
                })

                row.append(td);
                countercolindex++;
                k++;

            });
    
            main.append(row);
            
            row='';
            i++;
        });
    }
     body(array);
     $('table tbody tr')
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='cont'>
<table>
<thead>
</thead>
<tbody>
</tbody>
</table>
</div>

\$\endgroup\$
  • 1
    \$\begingroup\$ For a high number of rows, the performance cost will be high no matter how you do it. \$\endgroup\$ – FreezePhoenix Oct 11 '18 at 12:51
2
\$\begingroup\$

but 1k, 10k, 100k is different

If you take a step back from code and look at the bigger picture, nobody actually reads 100k table rows in one session. It would be 100 rows at best, then people start skimming. At that point, all the effort of rendering is for nothing.

One good example of this is Google. When you search for a term, it can return millions of matches. However, Google only renders the first 10 and paginates the rest away. Another would be log aggregation platforms like Scalyr or Sentry. Logs can be hundreds of megabytes worth of log messages, but it only renders the first hundred or so. The rest you can reach via search filters, sorts and pagination.

So my advice would be to render only a limited subset at a time. At the same time move your focus towards implementing search capabilities. You might want to look into Lunr for client-side search indexing capabilities.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.