Comparable functionality to Backbone.js but easier to implement?

Comparable functionality to Backbone.js but easier to implement?

idealienidealien Posts: 7Questions: 0Answers: 0
edited February 2014 in General
Hi,

I've used dataTables on a number of projects in the past and always found it quite easy to put together what I needed. Whether from the documentation or the deep forum examples. From what I've read of the 1.10 release notes and poked around that site it looks like that is going to be even more the case.

I'm working on a project that aims to build a UI that is reasonably similar to http://schedule.sxsw.com but with the added functionality to allow people to select their own itinerary. The conference its' initial use is for will have ~100 presentations over 3 days presenting ~500 papers. I put together an initial proof of concept with datatables 1.9 - http://live.datatables.net/EhUC/1/edit - that relied on TableTools and its' "sRowSelect": "multi" to allow selection.

I then designed a much more ambitious interface based on an intent to build it with Backbone.js with its' patterns for views and data models. That hasn't been terribly productive, and I am coming back to the idea that dataTables may be the way to go. What follows are a mixed series of questions that I haven't been able to find explicit answers for in 1.9 documentation or forum posts to date looking to achieve that.

Below are a mix of questions and loosely formed ideas on how I am thinking about implementing it. Hoping that some feedback before I start down that path will save me time and headaches - either with link to samples that I have not yet discovered on the forums or suggestions of better approach to look at. I'll definitely post the source back upon implementation for others to leverage if I'm able to build successfully...

1) Print only selected rows
In 1.9 the limitation of print to not support "bSelectedOnly": true was a concern. I didn't see anything in the release notes indicating a fix / support for 1.10 for that but would love to know that is the case?

2) LocalStorage w/o Editor?
That initial prototype was using the cookie for local storage. I don't need CRUD on the data that forms the schedules, but Editor has a great example use of localStorage - https://editor.datatables.net/release/DataTables/extras/Editor/examples/localstorage.html - is it possible to do similar functionality without Editor? Or how much would one have to turn-off in using Editor to only take advantage of the localStorage capacity?

3) Copying data between tables with validation and source table updates
Even if #1 is fixed, the new interface UI idea lends itself better to copying rows between tables with validation to check that the person has not already selected another row that has a conflict based on date / time. Any of the forum posts I found towards this were left with frustration or very small use case.

4) Update every other source table row based on user copy action
In a similar fashion to how live click events can be tied to images to show open/closed for display of additional row data (as my live datatable example has), I was thinking to show a +, - or ! on source table if user can add, remove or swap a presentation into their itinerary. That would also lead to re-draw / validation on every other row in table.

5) nested dataTables with multiple JSON table source?
In the live datatable above I have one hidden column showing "paper details" that gets shown on img.expander live click as a clone sub-row add-in. Are there any examples of doing a similar click event but then showing a nested sub-table / presentation? In that case having papers sortable by title + author is the interest.

6) Multiple dataTables with multiple JSON table source?
I (thankfully) have solid capability to modify the backend data structures to suit whatever front-end requires. The current live datatable shows one large JSON, but the new UI has view by presentation, by paper, by author, by location, by date/time that each have unique row presentation criteria. Starting to think that having separate localStorage tables which filter / pull results in as needed is a better route to go. A few small examples of what might be needed:
- View By Presentation: Each row lists all papers that have associated presentation ID in expanded view
- View By Paper: Each row lists the one presentation and its' date / start time it is associated to in expanded view
- View By Date/Time: Each row lists a time block, but sub-rows (presentations) should be selectable.
- Across all - Wherever presentation is shown, ability to add, remove, swap from itinerary based on schedule info.

7) Save Itinerary to AJAX
LocalStorage is great compared to cookies, but is device specific. If I can build all of the above reasonably, syncing the itinerary table selections via AJAX along with a user / pass combination would allow it to support cross-device use.

8) Pop-up detailed view
Rather than click to add sub-row, perhaps another way to present larger data is to present the hidden details in a modal window. Haven't searched the forums for this one as I only just thought of it after realizing how many of the questions above frame around sub-data display.

As I said - ambitious. But it speaks to the absolute quality and depth of datatables that the majority of questions are not "is this possible" but "how best to achieve" and hopefully that others have already explored / documented such items. Thanks in advance for any suggestions / answers anyone can provide.

Thanks,
J

Replies

  • allanallan Posts: 63,692Questions: 1Answers: 10,500 Site admin
    > 1) Print only selected rows

    As you note, this isn't yet supported, and DataTables 1.10 has no effect on that since that functionality is provided by the TableTools plug-in. The plan is to add support for it in either a forthcoming TableTools release, or more likely a breakdown of TableTools into individual components (buttons and row selection being the main ones).

    It would be possible to modify TableTools as it stands to filter the table on print view and remove that filter when disabling print view, which you might want to consider?

    > 2) LocalStorage w/o Editor?

    I'm afraid I don't really understand the question here. Editor adds CRUD to the table, but you say you don't want CRUD. That's fine, but what do you want localStorage to do in that case (since in the example you link to it is only used for CRUD). If you just want to store the data for a table in localStorage - then sure, that shouldn't be a problem.

    > 3) Copying data between tables with validation and source table updates

    Moving / copying data between tables is just a case of using the API - fnAddData, fnUpdate, fnDeleteRow. If you want to do validation, just perform whatever validation is needed before using the API methods.

    > 4) Update every other source table row based on user copy action

    Shouldn't be a problem - just tie your delegated (live) events to the API methods you need to use to achieve whatever action you need.

    > 5) nested dataTables with multiple JSON table source?

    Unfortunately the open / close in your example isn't working, but if you want an 'inner' DataTable, simply initialise it once your called fnOpen to add the data tot he table. There is no problem nesting as many DataTables as you want - although do note that they are all independent of each other.

    > 6) Multiple dataTables with multiple JSON table source?

    You could certainly do it that way. Just show / hide the different DataTables as needed. It might introduce a lot of duplicate code doing it that way, rather than trying to rearrange an existing table, but you know your data lot better than me!

    > 7) Save Itinerary to AJAX

    Just Ajax sync every time you do an update via the API :-)

    Allan
  • idealienidealien Posts: 7Questions: 0Answers: 0
    Thanks for the detailed feedback. I'm making solid progress on 3 & 4 now before bringing ajax and localStorage into the mix. A couple of smaller questions that are more about DRY (don't repeat yourself) concepts applied to datatables than anything else.

    A) Re-definining .dataTable in functions.
    I have two tables in page that are essentially the same other than the first (oTable) is pre-populated with content while the second (iTable) gets rows copied into it from the first. Within every function (in or out of doc ready) I can seemingly directly access oTable, but must re-define iTable in order to access it. I've included table creation and example button calls in code snippet below.

    [code]
    var iTable = $('#itinerary').dataTable( {
    "aoColumns": [
    { "mData": "id", "sTitle": "#" },
    { "mData": "title", "sTitle": "Panel", "sClass": "panel_title" },
    { "mData": "date", "sTitle": "Date", "sClass": "date" },
    { "mData": "startTime", "sTitle": "Start" },
    { "mData": "endTime", "sTitle": "End" },
    { "mData": "room", "sTitle": "Room" },
    { "mData": "building", "sTitle": "Building" },
    { "mData": "papers", "sTitle": "Papers", bVisible: false}
    ]
    } );

    $('#example tbody tr td.expander img').live('click', function () {
    var nTr = $(this).parents('tr')[0];

    //Q? This oTable is understood
    if ( oTable.fnIsOpen(nTr) ) {
    oTable.fnClose( nTr );
    this.src = "media/images/details_expand.png";
    this.attr("class", "open");
    } else {
    oTable.fnOpen( nTr, fnFormatDetails(oTable, nTr), 'details' );
    this.src = "media/images/details_contract.png";
    this.attr("class", "closed");
    }
    } );

    $("#itinerary tr").live('click', function () {

    var iTable = $("#itinerary").dataTable();
    //Q? Without re-definition iTable is not.
    iTable.fnDeleteRow( this );
    fnScheduleButtonUpdate(oTable, this, "remove");
    });
    [/code]

    B) Identifying same row moving between tables.
    I wrote a function fnScheduleButtonUpdate to walk through oTable and update the add/swap/remove icons for entire table based on whether each row matches the latest changed row (cTR - received as parameter). This works when triggering from oTable and passing the oTable row in which was clicked. Hoping there is a way to re-use the same function when triggered based on an iTable row click. Is there a better way / other option to crawl based on data than what I'm doing for this?


    [code]
    //Subset of oTable click event less validation on row click event that fnScheduleButtonUpdate works
    $('#example tbody tr td.selector img').live('click', function () {
    var sTR = oTable.fnGetData( $(this).parents('tr')[0] );
    iTable.fnAddData(sTR);
    fnScheduleButtonUpdate(oTable, sTR, "add");
    });

    //Full of iTable click event. fnDeleteRow works, but fnScheduleButtonUpdate does not
    $("#itinerary tr").live('click', function () {
    var iTable = $("#itinerary").dataTable();
    iTable.fnDeleteRow( this );
    fnScheduleButtonUpdate(oTable, this, "remove");
    });

    //Subset of fnScheduleButtonUpdate function
    function fnScheduleButtonUpdate( oTableLocal, cTR, actionType ) {

    var oNodes = oTableLocal.fnGetNodes();
    console.log("Button Update: " + actionType);

    if (oNodes.length > 0) {
    for (var i = 0; i< oNodes.length; i++) {
    oItem = oTableLocal.fnGetData(oNodes[i]);

    if((cTR["date"] === oItem["date"]) && (cTR["startTime"] === oItem["startTime"]) && (cTR["endTime"] == oItem["endTime"])) {

    j=i+1;

    //Find ID match
    if(cTR["id"] === oItem["id"]) {

    $("#example tr:eq(" + j + ") td.selector img").attr('src', 'media/images/details_remove.png').attr("class","remove");

    }
    }
    }
    }
    });
    [/code]

    Thanks,
    Jamie
  • allanallan Posts: 63,692Questions: 1Answers: 10,500 Site admin
    Hi Jamie,

    A) I don't see where `oTable` is defined anywhere - so based on the code above, it should be throwing an error about an undefined variable. I guess it is defined somewhere else? Regarding the redefinition of `iTable` - it looks like it should work in the code above, but it wouldn't if they were in different functions, since `iTable` is locally scoped. I presume the code above is clips, so I'm afraid I can't really say much more than that...

    B) You have a `oTableLocal` parameter for the function, so wouldn't you just add event handlers to your iTable that will pass in `iTable` as the local table? You could go further - and just pass in target and then use something like:

    [code]
    var hostTable = $(tr).parents('table').eq(0).dataTable();
    var targetTable = hostTable[0].id === 'itinerary' ?
    $('#theOtherTable').dataTable() :
    $('#itinerary').dataTable();

    // perform add / delete etc as needed from the host to the target
    [/code]

    then even the event handlers could be shared.

    Allan
  • idealienidealien Posts: 7Questions: 0Answers: 0
    Yes - I had tried to include relevant snippets. Have worked passed those issues and have got validation and table copying working solid. Also have most of the localStorage implementation working. The last few pieces which is challenging me deal primarily with the initial draw of the table pulling state from the localStorage and modifying rows that are not part of mRender which are "conflicts by date / time in schedule".

    I've included all relevant files at https://gist.github.com/Idealien/623152b7e449d8280834 - just had to put - in for filenames in place of / as gists don't allow sub-folder paths.

    Working / Process:
    - $(document).ready does localStorage detect and build of store
    - oTable aoColumns has mRender on first field calling presentationRenderer and fnDrawCallback of presentationButtonSetup
    - In presentationRenderer the link for btn-itinerary is default to class of btn-primary and text of + for an add event
    - in presentationButtonSetup I use $.each to loop through localStorage entries and set the class/text of any btn-itinerary (based on unique ID) to be class of btn-danger and text of x for remove event.

    I'm stalled in best approach at line 131 of schedule_local.js within presentationButtonSetup. I thought it might be something to do with using a custom filter to identify the rows which are conflict and then modify their presentation, but after the draw is complete I don't need the filters to stay applied.

    It also seems like I might be doing a number of manual things which datatables has built-in solutions for. Any suggestions on where to improve would be greatly appreciated.
  • idealienidealien Posts: 7Questions: 0Answers: 0
    edited February 2014
    Scratch that. Using fnRowCallback instead was all that I needed.

    The working example that matches against localStorage values to determine which type of icon (add, remove, swap) to present:

    [code]
    function presentationButtonSetup( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {


    var store = JSON.parse( localStorage.getItem('irspm2014_itinerary') );
    var classes = $('#btn-itinerary-' + aData["id"], nRow).hasClass('btn-success');


    $.each( store, function(){

    if ((this.date === aData["date"]) && (this.startTime === aData["startTime"]) && (this.endTime === aData["endTime"])) {

    if(this.id == aData["id"]) {
    $('#btn-itinerary-' + aData["id"], nRow).removeClass('btn-success').addClass('btn-danger').text("x");
    } else {
    $('#btn-itinerary-' + aData["id"], nRow).removeClass('btn-success').addClass('btn-warning').text("!");
    }
    }

    });
    }
    [/code]

    I still think I'm doing something wrong in how I declare store that I seemingly have to re-declare within each function I use it. But what works for now....works.
This discussion has been closed.