Datatables updating only rows without reloading ta

2019-08-08 21:08发布

问题:

BACKGROUND: I have a small jquery app that contains widgets. There are 2 types of widgets in this app and they are counter widgets and grid widgets. For grid widgets i am utilizing dataTables.

My app basically connects to a server and recieves various information such as widget names etc. So based on the information received i dynamically create pages for each widget. Things are working fine at the moment but i am facing a little problem.

Problem The issue i have right now is to do with my grid widgets which utilize dataTables api.From my server I receive the grid information in this format.

//EXAMPLE INPUT
/*
<?xml version="1.0" encoding="UTF-8"?>

<rows>

 <head>
 <column width="55" type="ro" align="left" sort="str">Player</column>
 <column width="55" type="ro" align="left" sort="str">State</column>
 <column width="55" type="ro" align="left" sort="str">Points</column>
 </head>
      <row id="1">
            <cell>Lebron King James</cell>
            <cell>Best Mode</cell>
            <cell>45</cell>
      </row>
</rows>
*/

Then i parse it to the appropriate table format (function createTableStringFromXML) so it works with the datatables.

My table is reloading every 3 seconds. So this is the problem.

Eventhough i want my table to update i think reloading the entire table is bad because not only does it look weird but i think it is not necessary. I was wondering is there way i can write some function that compares the old table with the new updated table and only updates rows that need update? So this way the entire table it self is not loaded?

MY HTML CODE

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
    <head>
        <title>NBA Fanatico</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="themes/tdMobile.min.css" />
        <link rel="stylesheet" href="themes/jquery.mobile.icons.min.css" />
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.0/jquery.mobile.structure-1.4.0.min.css" />
    <link rel="stylesheet" type="text/css" href="cssfinal/style.css" />


        <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.4.0/jquery.mobile-1.4.0.min.js"></script>


    <script src="dhtmxSuite/dhtmlxWindows/codebase/dhtmlxcommon.js" type="text/javascript"></script> 

           <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
       <script src="jquery.ui.touch-punch.min.js"></script>

   <!-- MAIN JS SCRIPT CONTANS CODE FOR COUTNER WIDGETS, TABLES , AJAX REQUEST FOR GETTING DATA-->

     <script src="dynamic.js"></script>



<!-- SCRIPTS FOR DATA TABLES -->

<!-- DataTables CSS -->
<link rel="stylesheet" type="text/css" href="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables.css" />



<!-- DataTables -->
<script type="text/javascript" charset="utf8" src="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.min.js"></script>




    </head>
    <body>

    <!-- PAGE 1 -->
        <div data-role="page" data-theme="a" id="page1">
            <!-- <div data-role="header" data-position="fixed">
                <h1></h1>
            </div> -->


            <div data-role="content" data-theme="a">




          <div class="login-box" id="login">



             <div id="loginprompt">
                <div id="header">


            <h3>Basketball Fanatico</h3>

        </div>

                </div>
        <form method="GET">

                <div id="username" data-role="fieldcontain">     
                    <input type="text" name="username" placeholder="Username" />
                </div>
                <div id="password" data-role="fieldcontain">   
                   <input type="password" name="password" id="txtId" placeholder="Password"/>
                </div>
                <div id ="loginbtn">
                    <a data-role="button" id="log" data-theme="a" href="#page2" data-transition="slide">LOGIN</a>
                </div>
            </form>

            <br />


</div>

            </div>


            </div>

        </div>


<!-- PAGE 2 -->

<div data-role="page" id="page2">

  <div data-role ="header" data-position="fixed" data-theme="a"> 
    <a data-iconpos="notext" href="#panel" data-role="button" data-icon="bars"></a>

  <h1 class="ui-title" role="heading">Basketball Fanatico</h1>
    <div class="ui-btn-right"  data-type="horizontal">
      <a data-iconpos="notext" href="#page2" data-role="button" data-icon="home" ></a>
      <a data-iconpos="notext" href="#page1" data-role="button" data-icon="delete" ></a>
    </div>
</div>



            <div data-role="content" id="page2content"> 

                <ul data-role="listview" data-inset="true">
                    <li data-role="list-divider" data-theme="a">WELCOME!</li>
                    <li>Use the menu on the left to navigate <br />and configure the various options.</li>                  
                </ul>


            </div>

        </div>

        <div data-role="panel" id="panel"  data-position="left" data-theme="a" data-display="push">
           <!--  <div> -->
                <div id="nav"><h3>Navigation</h3>


                 <hr>
                <label>

                <input id="chkSort" type="checkbox" checked="true"  />Allow sorting</input>
                </label>
                <hr>
            </div>
            <div id="items" data-role="button">
                <!-- Insert Parsed Widget Names Here -->
                <a href="#page1" data-transition="fade" data-theme="a" data-role="button">LOG OUT</a>
            </div>

        <!-- </div> -->


</div>



    </body>
</html>

MY JS

        var widgetNames = new Array();
        var widgetId = new Array();
        var pageId = ''



        $( document ).on( "pagecreate", function() {
            $( "body > [data-role='panel']" ).panel().enhanceWithin();


              //Format the grid as required
              $('#example2').dataTable( {
                "bPaginate": false,
                "bFilter": true,
                "bAutoWidth": false,
                "oLanguage": { "sSearch": "" } 
               } );

              $('.dataTables_filter input').attr("placeholder", "Search");
              $('.dataTables_filter').css('float','none');    
              $('.dataTables_filter').css('padding-right','0px');    
              $("#example_filter").detach().prependTo('#header1');    

        });

        $(document).on('pagecreate', '#page1', function() {

           // $( ":mobile-pagecontainer" ).on( "pagecontainershow", function( event, ui ) {
           //                    pageId = $('body').pagecontainer('getActivePage').prop("id"); 
           //                    alert( "The page id of this page is: " + pageId );
           //                    });


            $("#log").on('click', function(){

                $.ajax({
                    url: "script.login",
                        type: "GET",
                        data: { 'page':'create_user', 'access':'user','username':$("input[name='username']").val(), 'password':$("input[name='password']").val()},
                        dataType: "text",
                        success: function (html) {
                            //console.log(html);


                            widgetNames = new Array();
                            widgetId = new Array();
                            var res = html.match(/insertNewChild(.*);/g);



                            //Get each widget name and ID and assign to values in an array
                            for(var i =0;i<res.length;i++){
                                //alert(res[i]);
                                var temp = res[i].split(',');
                                if(temp.length >= 3){
                                  widgetNames[i] = (temp[2].replace('");','')).replace('"','');
                                  widgetId[i] = temp[1].replace("'","").replace("'","").replace(/ /g,'');
                                }           
                            }

                            var AllWidgets = ''
                            var testwidget = new Array();



                            //Loop through the html returned and get the data relevant to each widget... save in temp array                            
                            var tempWidgetContent = html.match(/w\d+\.isHidden(.*)\(\) == false\)[\s\S]*?catch\(err\)\{ \}/gm);
                            for(var i =0;i<tempWidgetContent.length;i++){
                                  var widgetContent = tempWidgetContent[i].substring(tempWidgetContent[i].indexOf('{')+1);
                                 //alert(widgetContent);

                                 //This alone handles coutners...
                                  testwidget[i] = widgetContent.replace("site +","");

                                  //replace the code for a grids...
                                  if(testwidget[i].indexOf('grid') > 0){

                                    testwidget[i] = CreateGridUpdateFunction(testwidget[i],i);
                                  }


                            }



                            var widgetPart =  new Array();

                            //Assume we have widget names, ids, and loading data in 3 arrays
                            //Loop through and create the necessary page.
                            for(var i = 0; i<widgetNames.length; i++){




                              if(testwidget[i].indexOf('hi') > -1){
                                // alert('WORKING');
                                var pageHeaderPart = "<div data-role= 'page' id='"+widgetId[i]+"' data-pageindex='"+i+"' class='dynPageClass'><div data-role='header' id='header1' data-position='fixed' data-theme='a'><a href='#panel' data-icon='bars' data-iconpos='notext' class='ui-btn-left'></a><a href='#' data-icon='search' id='search' data-iconpos='notext' class='ui-btn-left' style='margin-left: 35px'></a><h1>BASKETBALL FANATICO</h1><a href='#page1' data-icon='delete' data-iconpos='notext' class='ui-btn-right'></a><a href='#page2' data-icon='home' data-iconpos='notext' class='ui-btn-right' style='margin-right: 35px;'></a></div><div data-role='content'>";
                              }

                              else{

                               var pageHeaderPart = "<div data-role='page' id='"+widgetId[i]+"' data-pageindex='"+i+"' class='dynPageClass'><div data-role='header'data-position='fixed' data-theme='a'><a data-iconpos='notext' href='#panel' data-role='button'data-icon='bars'></a><h1 class='ui-title'role='heading'>BASKETBALL FANATICO</h1><div class='ui-btn-right' data-type='horizontal'><a data-iconpos='notext' href='#page2' data-role='button'data-icon='home'style=\" margin-right:5px; \"></a><a data-iconpos='notext' href='#page1' data-role='button'data-icon='delete'></a></div></div><div data-role='content'>";
                              }


                               var pageFooterPart = "</div><div data-role='footer' data-position='fixed'><span class='ui-title'><div id='navigator'></div></span></div></div>";


                               if(testwidget[i].indexOf('hi') > -1){
                                   // alert('i am a grid');

                               var check = "<div data-role='tbcontent'><ul data-role='listview'data-insert='true'><li data-role='list-divider' data-theme='a'>"+widgetNames[i]+"";

                               }


                               var check = "<div data-role='content'><ul data-role='listview'data-insert='true'><li data-role='list-divider' data-theme='a'>"+widgetNames[i]+"</div>";

                               if(testwidget[i].indexOf('counterValue') > 0){
                                 // alert('i am a counter');

                                  widgetPart[i] = '<DIV style=\" text-align: center; background-color:#EDEDED; padding-bottom: auto;  font-size: 55pt;\" id=widgetContainer_'+widgetId[i]+'></DIV><SCRIPT>' + 'function UpdateWidgetDiv'+widgetId[i]+'() {' + testwidget[i] + '$(\"#widgetContainer_'+widgetId[i]+'").html(counterValue);' + '}' + '</SCRIPT>';




                               }
                               if(testwidget[i].indexOf('hi') > -1){
                                // alert('i am a grid');

                                   widgetPart[i] = '<DIV id=widgetContainer_'+widgetId[i]+'></DIV><SCRIPT>' + 'function UpdateWidgetDiv'+widgetId[i]+'() {' + testwidget[i]  + '}' + '</SCRIPT>';
                               }
                               else {
                                  widgetPart[i] = '<DIV style=\" text-align: center; background-color:#EDEDED; padding-bottom: auto;  font-size: 55pt;\" id=widgetContainer_'+widgetId[i]+'>I dont know what I am</DIV>';
                               }

                               AllWidgets +='<a href="#'+widgetId[i]+'" class="widgetLink" data-theme="b" data-role="button" >'+widgetNames[i]+'</a>';                         

                                             var makePage = $(pageHeaderPart + check + widgetPart[i] + pageFooterPart);

                               makePage.appendTo($.mobile.pageContainer);
                            }
                            $('#items').prepend(AllWidgets).trigger('create');


//Widget Update Function

function UpdateActivePage(){
    //get active page
    pageId = $(":mobile-pagecontainer" ).pagecontainer('getActivePage').prop("id");
    //figure out index
    var idx;
    for (var i=0; i<widgetId.length; i++){
       if (widgetId[i] == pageId){
          idx = i;
          break;
       }
    }

//alert(pageId);
    //run your update
    //alert("RUNNING:");
    eval(testwidget[idx]);
    //alert('Updateing active page');
    $("#widgetContainer_" + pageId).html(counterValue);


        $('#grid_'+idx).dataTable( { 
          "bPaginate": false,
          "bFilter": true,
          "bAutoWidth": false,
          "oLanguage": { "sSearch": "" } 
        } );
       $('.dataTables_filter input').attr("placeholder", "Search");
       $('.dataTables_filter').css('float','none');  
       $('.dataTables_filter').css('padding-right','0px');   
       $("#example_filter").detach().prependTo('#header1');   


}


function CreateGridUpdateFunction(oldUpdatefunction,thisWidgetID)
{




    var updateLines = oldUpdatefunction.split("\n");
    var updateFunctionCode = "";
    for (var i=0; i<updateLines.length;i++)
    {
        if(updateLines[i].indexOf(" var url = ") > 0)
        {

            var updateURL = updateLines[i];
            if(updateURL.indexOf("&windowWidth=") > 0){
                updateURL = updateURL.substr(0,updateURL.lastIndexOf("&windowWidth=")) + "';";

            }

            updateFunctionCode += updateURL;   
            updateFunctionCode += "   var loader = dhtmlxAjax.getSync(url);";   
            updateFunctionCode += "   if(loader.xmlDoc.responseText.length > 0){";

            updateFunctionCode += "     counterValue = createTableStringFromXML(loader.xmlDoc.responseText,"+thisWidgetID+");";
            updateFunctionCode += "   }   ";


        }
    }


    return "var counterValue = \"hi\"; "+updateFunctionCode ; 
}


$(":mobile-pagecontainer" ).on( "pagechange", function()  { UpdateActivePage(); } )



setInterval(UpdateActivePage, 3000);



                        }

                });

            });
        });



//Returns a bool indicated if the (space trimmed) string starts with needle.
function startsWith(searchString,searchVal){
  var search = searchString.trim();
  return search.indexOf(searchVal) >= 0;
}

function createTableStringFromXML(serverXML,thisWidgetID){


  console.log(serverXML);

  var xmlLines = serverXML.split("\n");
  var returnTable = "";


  for (var i=0; i<xmlLines.length;i++)
  {
     if(startsWith(xmlLines[i],"<rows"))
     {
        returnTable += "<table cellpadding=\"2\"  cellspacing=\"2\" border=\"0\" class=\"display\" id=\"grid_"+thisWidgetID+"\" width=\"100%\">";
     }
     else if(startsWith(xmlLines[i],"</rows>"))
     {
        returnTable += "</tbody></table>";
     }
     else if(startsWith(xmlLines[i],"<head>"))
     {
        returnTable += "<thead><tr>";
     }
     else if(startsWith(xmlLines[i],"</head>"))
     {
        returnTable += "</tr></thead><tbody>";
     }
     else if(startsWith(xmlLines[i],"<column"))
     {
        returnTable += "<th>"+xmlLines[i].match(/>(.*?)</i)[1]+"</th>";
     }
     else if(startsWith(xmlLines[i],"<row"))
     {
        returnTable += "<tr>";
     }
     else if(startsWith(xmlLines[i],"</row"))
     {
        returnTable += "</tr>";
     }     
     else if(startsWith(xmlLines[i],"<cell"))
     {
        returnTable += "<td>"+xmlLines[i].match(/>(.*?)</i)[1]+"</td>";
     }


console.log(returnTable);

  }


   return returnTable ;

}

Please advice on how to achieve this. I am sorry if you have not understood my question so please ask me again. I am only using HTML and JS for couple of months so i am band new to this and that also might be the reason why my question might sound silly to some of you so sorry in advance. I apologize for my poor english please let me know if you dont understand. Thanks.

回答1:

Updating the table every 3 seconds could cause performance issues, especially if you have lots of rows!

If you want to do it, you can iterate through the rows in the update XML and then write the values to the individual cells in the table.

DEMO

In my example, the table is already there with row ids as data attributes on the row element. I am updating once on a button click instead of every 3 seconds on a timer, but the parsing would be the same.

$("#update").on("click", function(){
    var $trows= $('#example tbody tr');       
    var xmlDoc = $.parseXML( xmlstring );
    var $xml = $( xmlDoc );  

    $xml.find("row").each(function(index){            
        var id = $(this).prop("id");            
        var $cells = $(this).find("cell");
        var c1 = $cells.eq(0).text();
        var c2 = $cells.eq(1).text();
        var c3 = $cells.eq(2).text();

        //get row in table with this id
        var $rowtd = $('#example tbody [data-id=' + id + '] td');
        $rowtd.eq(0).text(c1);
        $rowtd.eq(1).text(c2);
        $rowtd.eq(2).text(c3);
    });  
});

The code loads the XML string into an XmlDocument and then creates a jQuery object from the document. Next I iterate through all the Xml Nodes called "row" getting the id and the 3 cell texts. Then I find the row in the existing table with the same Id and write the texts into the existind TDs in the row.

You will need to test the performance of this given the normal number of rows you have and the types of devices you plan to support.