jQuery UI "Progressbar" in column

jQuery UI "Progressbar" in column

GregPGregP Posts: 500Questions: 10Answers: 0
edited January 2011 in General
Hi Allan (and forum members!),

Implementing DataTables in a web application which has a "progress" view. There are many ways to skin the cat, and I have successfully gotten the DataTable to render the progress as a bar rather than a text value.

However, I'm keen to use the jQuery UI theming capabilities, which is causing two different problems. Solving either of these would solve the issue:

1. If you simply use fnDrawCallback to call jQuery UI's progressbar() on the selected columns, the column becomes double-striped. So if you're in a row that has a blue stripe, when you get to the progress column it will contain both a blue and white stripe. I suspect it's an nth-child selector issue related to progressbar() inserting a whole new pair of divs to make the progressbar.

2. Alternatively, you can have your server return HTML with the corresponding classnames in the cell content ("ui-progressbar-value ui-widget-header ui-corner-left"); however, the progressbar will only visibly render the widget-header styling because the jQuery UI theme for progress bars relies on the parent (in this case, the TD element) having the class "ui-progressbar".

#2 seems like it SHOULD be the easier one, but I don't know how to tell DataTables to add "ui-progressbar" to the TD element in a given column.

The "throw in the towel" method for fixing #1 would be to not use striping. ;-)

Thanks for taking the time to read this!
Greg

Replies

  • GregPGregP Posts: 500Questions: 10Answers: 0
    Actually, a few moments of experiments later, and #2 is really going to be the way to fly. #1 can result in a rendering 'blip' as the column comes in as text and is quickly updated to be a bar. It occurs to me that you could do this with hidden columns somehow, but really the easiest is to simply have that column's TD have the ui-progressbar class on page render.

    Could just addClass with the draw callback, but I think there may still be a rendering artifact as the bar changes from "default header" to "progressbar" styling.
  • GregPGregP Posts: 500Questions: 10Answers: 0
    D'oh, forget me with regards to the double-striping. The theme I was using had a GIF specified as the background that was screwing with everything.

    So the only remaining question is: is there a way to include that class as part of the table drawing function (ie. is there a parameter I'm missing?) or do you have to do it with jQuery and addClass()?

    Thanks!
    Greg
  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin
    If it is on a per column and only for a temporary period, I'd say that that just a jQuery expression with addClass would do the trick nicely. Mucking around with the DOM is very much approved of ;-) (although obviously removing TR /TD elements might make DataTables hiccup...).

    Allan
  • GregPGregP Posts: 500Questions: 10Answers: 0
    edited January 2011
    Heh, thanks Allan! We're polling for data once every 2 seconds. Would poll even more often if we could keep the UI responsive, probably. Traversing the dom and updating the styles causes a visible 'flicker'.

    However, there's a positive conclusion to the story: your implementation of the UI Themes is fairly robust and it was actually an unconventional theme that was causing the issue. By styling it per convention, I don't need to traverse the dom, I can send back the in the JSON and bickity-bam, renders like a charm, no flicker.
  • GregPGregP Posts: 500Questions: 10Answers: 0
    edited January 2011
    The 'positive conclusion' has been foiled. The back-end team doesn't want to inject any tags for me. Which if I'm being honest makes sense-- keep the model and the view separate and all that....

    I have a function that's meant to handle upgraded rendering to individual cells:

    [code]
    "fnDrawCallback": function() {
    $this = $('#task_progress td:nth-child(5n+5)');
    $this.each(function(){
    thisValue = Number($(this).text());
    $(this).html(function() {
    progressString = '';
    return progressString;
    });
    })
    }
    [/code]

    However, for whatever reason, Firefox won't apply the rendering. I can see it in the DOM, but Firebug shows it as a 'non-visible' element. And, the original number in its integer state is still visible.

    Simplifying the example so that a simple string is returned instead, "foo", and again it can be seen in the DOM according to Firebug, but it does not render to the screen.

    Flip over to a webkit browser, and it works fine.

    So, in this case, manipulating the DOM after render doesn't seem to produce results in Firefox. There's a bigger issue, though... it just itches at the back of my head as out-of-order to do it that way. I would love there to be some way of inserting the code before the table is even pushed into the DOM.

    Data --> build table --> change table --> show table (or depending on how you look at it, even Data --> build table --> show table, with new HTML already in place during the building phase)

    By selecting the elements and modifying them after the render,

    Data --> build table --> show table --> change table

    it just strikes me as inefficient.

    I don't mind trying my hand at inserting additional rendering information into datatables.js itself, but it's so modular (probably a good thing!) that I can't tell where to hook in. Or is there already a function that could help me that I've overlooked? It's such a deep plugin that it's entirely possible!
  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin
    The closest callback (and it might be what you want, looking at the above code) is fnRowCallback ( http://datatables.net/usage/callbacks#fnRowCallback ) which will give you the DOM element before it is drawn, allowing you to manipulate it as you wish. There isn't however a function which will let you manipulate the DOM just before everything is shown. If you do want to do that, have a look in _fnDraw where it does:

    [code]
    oSettings.nTBody.appendChild( nAddFrag );
    [/code]
    That is where the TR elements are added to the table for display. But I think fnRowCallback looks more promising :-)

    Allan
  • GregPGregP Posts: 500Questions: 10Answers: 0
    I'll give your suggestions a try. A bit of an update of my own: it seems that Firefox doesn't support innerHTML (and therefore .html() ) on TD elements. I might be able to use this as leverage to convince the back-end team to at least throw me a freakin' div if not the whole shebang. ;-)

    Cheers,
    Greg
  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin
    I'm surprised by that - DataTables uses innerHTML on TD elements itself, and I've not hit a problem with it. I can certainly imagine it wouldn't like outerHTML, but I'm surprised that innerHTML is throwing it off.

    Allan
  • GregPGregP Posts: 500Questions: 10Answers: 0
    edited January 2011
    You're right to be surprised, but I'm now stumped. Here's my experiment:

    Draw a table on the page with DataTables, and another one just a plain ol' HTML table.

    Execute the following from Firebug's console:

    $('td').html('a cell');

    It should select every TD in the entire page and change its contents to the string "a cell". This is exactly what happens to the table that's pure HTML, but not to the table rendered with DataTables! It's the weirdest thing. And if I use Firebug to inspect the elements, I can see in the Firebug pane the TD elements with "a cell" in-between the tags, but it is not actually rendered to the page itself.

    Thinking it was Firebug itself, I disabled it, but still no render.

    It's the darndest thing, and I have no idea what to do if I want to get around it using my existing method; however, I'm about to try the fnRowCallback method. We'll see how that goes!

    [edit: it's worth noting that I also use jQuery UI to style the DataTables table... not sure if that could affect anything, since as far as I know all it does is add some classes]
  • GregPGregP Posts: 500Questions: 10Answers: 0
    Still no idea why I can't target the TDs after the table is drawn, but the callback you brought my attention to fits in perfectly with what I envisioned in the first place, and also works in Firefox! So, bit of weirdness on the part of the browser or jQuery (not sure which, really), but the final callback looks like this:

    [code]
    "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
    /* Turn the fifth row -- progress -- into a progressbar with jQuery UI styling */
    progressString = '';
    $('td:eq(4)', nRow).html(progressString);
    return nRow;
    }
    [/code]

    Ideal!
  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin
    Good stuff! We'll take what works :-). Certainly the way you've used fnRowCallback is exactly the sort of thing it was designed for, so looks like a good solution to me.

    Regards,
    Allan
This discussion has been closed.