5

If I have a table:

<table>
    <thead>
        <tr>Col1</tr>
        <tr>Col2</tr>
        <tr>Col3</tr>
    </thead>
    <tbody>
    </tbody>
</table>

What is the fastest, most efficient way to fill the tbody with tr elements containing my data from a database using a Jquery Ajax. (unless you have a better way)

Return html code from the webservice OR dynamically create the html code in Javascript?

Also I have to support the user "drilling down; i.e. either clicking a > or double clicking the row to open a pane to show some more information. (including another table and some detail information returned by a separate webservice)

All ideas welcome!

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
kralco626
  • 8,456
  • 38
  • 112
  • 169

5 Answers5

3

Unless you need to create literally thousands of rows, performance is just not a concern here. Where you generate the markup is really a design decision. You can generate the markup:

  • Server-side, in your templating language of choice (ASP.NET, PHP, JSP, Django templates...) or
  • Client-side, using JavaScript templates ($.tmpl, Mustache...)

Client side will (theoretically) decrease the load on your server, but this too is likely not a relevant issue. Whichever flavor you choose, you should use that consistently throughout your app unless there is a truly compelling reason to do otherwise.

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • How do you draw that conclusion? The ajax call could return HTML data. – Matt Ball May 18 '11 at 13:33
  • @Matt Ball - I'm operating on the assumption that putting the markup in the webservice is not the best approach. You're right, my statement was misleading. I should have clarified. – SquidScareMe May 18 '11 at 13:36
  • 2
    @SquidScareMe: The server doesn't whether it's an ajax call or not. Is all HTTP to it, baby. – Xhalent May 18 '11 at 13:37
  • @Squid and Matt - as to the html markup in the webservice, I think I could do it and not totally violate the principal of keeping the data and UI separate. I could have a helper method that creates the html, so that there is still a standalone web service for the data. – kralco626 May 18 '11 at 13:42
  • @Matt - I wont have thousands of rows, maybe hundrends, and I have has issues with IE8 being extremely slow with javascript stuff. Especially DOM manipulation, like adding a large chunk of html to the DOM... – kralco626 May 18 '11 at 13:43
  • @kralco I agree. Using some sort of MVC pattern/library/framework then it's generally easy to keep the data (the M) separate from the UI (the V). – Matt Ball May 18 '11 at 13:44
  • 1
    @kralco: it's not a big deal so long as you minimize the number of DOM manipulations. You can build up one big HTML string and insert it once rather than insert every row individually - much better performance. – Matt Ball May 18 '11 at 13:45
  • yes, I still had issues with IE8 doing exactly that. Of course, I was likely doing something else wrong... – kralco626 May 18 '11 at 13:46
  • 2
    I agree that a web services emitting HTML mark-up is just flat out wrong because it doesn't support good [separation of concerns](http://www.google.com/url?sa=t&source=web&cd=1&sqi=2&ved=0CCEQFjAA&url=http%3A%2F%2Fen.wikipedia.org%2Fwiki%2FSeparation_of_concerns&rct=j&q=separation%20of%20concerns&ei=sM7TTb7bK4uCtgf-5v2PCg&usg=AFQjCNFjPCAoeZtZUsEK1uTqlMlgN2QTOg). I would rather have a web service that returns JSON, that way it can be manipulated easily to fit any _evolving_ design requirements over time. You can always implement a client-side mechanism that loads the data progressively. – pixelbobby May 18 '11 at 13:51
2

Returning HTML from the webservice tightly couples your code. The better of the two ways is to create the HTML in Javascript.

SquidScareMe
  • 3,108
  • 2
  • 24
  • 37
2

You can use jQuery .ajax() call to return the data in a JSON object and use the .tmpl() templating plugin to render the html.

You can view the templating documentation here : http://api.jquery.com/tmpl/

Update: I posted an example as an answer to another question

Community
  • 1
  • 1
ShaneBlake
  • 11,056
  • 2
  • 26
  • 43
2

I work on a large-scale enterprise portal that uses jQuery and AJAX. I've implemented jQuery Templates and the jQuery TableSorter plug-in to facilitate this. Here's some example code:

Javascript (Data Provider): Data.Lists.js

myorg.data.list.GetListItems ({
    webURL: "http://our.awesome.portal.com/Lists",
    listName: "Projects List",
    caml: caml,
    CAMLRowLimit: 6,
    callback: function(data) {
        var list = {};
        //code here that formats some data before binding
        list.items = data;
        var templateHtml = $('.ptMyProjects').html()
        .replace("<!--", "").replace("-->","");
        var html = $.tmpl(templateHtml, list);
        $('.ptMyProjects').html(html);
        //make sortable table
        $('.ptMyProjects .tablesorter').tablesorter({
            sortList: [[0,0]],
            headers: {3: {sorter: false}},
            widgets: ['zebra']
        });
        //class last row
        $('.ptMyProjects .tablesorter thead th').last().addClass('last');
        //add hover effect
        $('.ptMyProjects .tablesorter tbody tr, .tablesorter thead .header').hover(function(){
            $(this).addClass('hover');
        }, function(){
            $(this).removeClass('hover');
        });
        //add tooltips
        $('.ptMyProjects .vg_icon').tipsy({gravity: 's'});
    }
});

HTML (the template)

<div class="ptMyProjects ptTemplate">
    <!--
    <table class="tablesorter" border="0" cellpadding="0" cellspacing="0">
        <thead>
            <tr class="gradient_gray">
                <th>Title</th>
                <th>Status</th>
                <th style="border-right: none;">Progress</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody>
        {{if items.length > 0}}
            {{each items}}
                <tr class='item' recordid="${ows_ID}">
                    <td ><a class='{{if ows_Critical_x0020_Project == "1"}}critical{{/if}}' href="${DisplayURL}">${ows_Title}</a> </td>
                    <td class="status">
                        <a href="#" class="pstatus">${ows_ProjStatus}</a>
                        <div style='display: none;'>
                            {{if ows_ProjComments}}
                                <div style="padding-bottom: 10px;">${ows_ProjComments}</div>
                            {{/if}}
                            <div style="font-weight: bold;">Lasted Edited By ${Editor}</div>
                            <div style="font-style: italic;">${when}</div>
                        </div>
                    </td>
                    <td>
                    <div class="ui-widget-default">
                        <div class="progressbar" value="${ows_PercentComplete}" style="height:100%;"></div>
                    </div>
                    </td>
                    <td class="actions">
                        {{if ows_ProjStatus != "Completed"}}<a href="#" class="vg_icon tick" title="Mark Completed"></a>{{/if}}
                        <a href="${EditURL}" class="vg_icon pencil" title="Edit"></a>
                        <a href="#" class="vg_icon comment" title="Comments"></a>
                    </td>
                </tr>
            {{/each}}
        {{else}}
            <tr><td colspan="4">You have no projects.</td></tr>
        {{/if}}
        </tbody>
    </table>
-->
</div>
Krupesh Kotecha
  • 2,396
  • 3
  • 21
  • 40
pixelbobby
  • 4,368
  • 5
  • 29
  • 49
  • I get what the Jquery/javascript code is doing in the callback function. However, what is that `Data.Lists.js` and `GetListItems` stuff? – kralco626 May 18 '11 at 13:56
  • As an aside, with table sorter there is no way to get excel like filtering, is there? Also expanding the table so I can show detail information would also be difficult I think? Adding another row for detail information would mess up the sorting... – kralco626 May 18 '11 at 13:57
  • I created a wrapper class that consolidates our `$.ajax` calls. This is good because we can update the data layer in one location. For example, jQuery overhauled the entire `$.ajax` namespace in the latest version, and instead of changing all the ajax throughout the site, we just updated the data class files :) our data classes are structured like so: `data.js`, `data.lists.js`, `data.users`, `data.groups.js`, `data.cache.js`, etc... – pixelbobby May 18 '11 at 13:59
  • You could write _excel-like-filtering_ custom (as I've done before) or implement a plug-in. Adding another row may conflict with sorting but I would handle it differently. For example, on one of our tables, when a user clicks on an action we just make another ajax request and show more information in a tooltip or pop-up modal div. – pixelbobby May 18 '11 at 14:02
  • ah yes, i see. We did a similar thing, just on a smaller scale, I have a function that takes in the basic stuff like the service name, parameters, success and fail callbacks... So I would only have to change something once in that function. Not as good as what you did however... :-p – kralco626 May 18 '11 at 14:04
  • Ya can't do the popup or tooltip for this. I need to display another detail table, along with a detail div that has a LOT of information. I designed the prototype using Telerik RadGrid and their PageView within the grid. Clients liked it as a prototype, but I think it has too many issue to go live with that design... http://stackoverflow.com/questions/6044259/telerik-radgrid-persist-client-state-on-sort-paging-filter – kralco626 May 18 '11 at 14:06
  • My approach to things like this is never _one solution fits all_ but starting with a re-usable component or module and then adding other modules to it as design and requirements evolve. I've used Telerik controls before. Personally, I'd rather build my own stuff or use many of the 3rd party jQuery controls out there. I'm entirely opposed to C# (server-side) generated `HTML/CSS/JS`. If the details are in a `
    ` I don't see what the problem is. You can put the div wherever you want, make it appear directly under the row, etc...
    – pixelbobby May 18 '11 at 14:13
  • "You can put the div wherever you want, make it appear directly under the row" how? with absolute positioning? that seems like a very bad strategy... It would not move the rest of the rows of the grid down to start... – kralco626 May 18 '11 at 14:30
  • http://stackoverflow.com/questions/1502014/table-sorter-to-sort-when-i-have-more-rows-in-thead - solves the filtering issue though... – kralco626 May 18 '11 at 14:34
  • not exactly. If you position the `
    ` under the row it would look uniform. You don't have to inject the `
    ` or `` into another `
    `. There are other, much cooler ways, and believe me, I know exactly what you're trying to do; I've created a feature like that several times in my career. Also, you can still put the detail `
    ` in the main `
    ` in the `
    ` and still have sorting.
    – pixelbobby May 18 '11 at 15:16
  • I thought I actually had a question about what a good way to do this was a while ago... How exactly would you do this? – kralco626 May 18 '11 at 16:25
  • Well, first I would recommend considering the [`jQuery Position`](http://api.jquery.com/position/) method. You can get the reference of the table row like so: `$('#myTable tr').click(function(){ $('#myDiv').load('data.aspx?id=5').css({top:, 0}); //where 0 is the calculated position of the row }); ` I recommend using the same `
    ` element and just loading new data and changing the position. Man, I hope I earned a checkmark for this :]
    – pixelbobby May 18 '11 at 16:33
  • does this use absolution positioning? what would happen to the rows below the one in question? what would happen when the row in question moves? In the case of sorting... – kralco626 May 18 '11 at 16:36
  • The idea is that you use a single element like so `
    `. When a row action is clicked such as _view details_, you would populate the div with the details, position it correctly, and then `show()` it. On your sort event you can simply hide the element. This is a usability preference. I would prefer not to see a potentially large element jumping around on sorting. Lol, this is the longest comment thread I think I've ever been apart of...
    – pixelbobby May 18 '11 at 16:43
  • Check some of my questions, I think I have longer. :-p Anyways, I posted a new question: http://stackoverflow.com/questions/6048207/how-to-create-a-div-that-apears-below-a-table-row – kralco626 May 18 '11 at 16:50
1

This solution works extremely well for me.

I simply retrieve a two dimension JSONed array from an AJAX PHP call.
(Using the php function json_encode())

Then simply iterate over the array to construct insertable table rows. as shown here.

$.post("./pdo_select.php", {post_query : view_q }, function(data) {
            var textToInsert = '';
            $.each(data, function(row, rowdata) {
               textToInsert += '<tr>';
               $.each(rowdata, function (ele, eledata){
                  textToInsert  += '<td>' + eledata + '</td>';
               });
               textToInsert += '</tr>';
            });
            $("#questions_table").append(textToInsert);

}, 'json'); 

Note the additional 'json' parameter.

The whole table can be quiet easily manipulated with standard jQuery, from adding a header row, turning one or more rows or tables into input fields.

I guess you don't have to use PDO routines to obtain the details from the database if you don't want to.

Below is a image of a table constructed using the technique listed above enter image description here

Sydwell
  • 4,954
  • 1
  • 33
  • 36