fnUpdate when using deep property reading for a data source

fnUpdate when using deep property reading for a data source

jamjon3jamjon3 Posts: 22Questions: 0Answers: 0
edited May 2011 in DataTables 1.8
When using deep property reading, I tried to use a fnUpdate like this:

[code]
connectionSourceDataTable.fnUpdate(singleObjOfArray, nRow, 0 );
[/code]

I get this error:

DataTables warning (table id = 'connectionSourceTable'): An array passed to fnUpdate must have the same number of columns as the
table in question - in this case 4

Looks like DataTables is still expecting an array as a row for the "fnUpdate" function. My instinct would be to update the underlying data object (in case I need it later for internal evaluations in "fnRowCallback" where I might call something like aData.connection.connectionId and other object properties in that processing).

Replies

  • allanallan Posts: 61,438Questions: 1Answers: 10,052 Site admin
    Heh - I partly implemented that this morning, and them removed it. I can't quite decide if passing in the full original object structure is the right thing to do or not - I had been thinking about offering that kind of functionality as a plug-in option.

    The reason I was a bit concerned was that I think that it's going to be quite difficult to implement fully and correctly. Although I suppose it could be that the full object is just replaced and then effectively do an update on each column... That might be best - added to the list...

    Regards,
    Allan
  • jamjon3jamjon3 Posts: 22Questions: 0Answers: 0
    I figured I was treading into some difficult algorithms. I was _guessing_ that, not knowing exactly how it was going to be evaluated, that I had to be consistent with the deep properties I setup on the columns so I had better make sure those references were still good while updating it. Also, I've been using other deep properties not used in my columns in my "fnOpen" calls too (along with "fnRowCallback"). That has been super helpful as, in the past, I'd create a hidden column with a JSON.stringify'ed object to store "extra" data I would use in those places. Code is SO much cleaner now so THANK YOU!!!!

    Hope I'm not being a pain but I will get you one of your Amazon books on my next paycheck (friday, aka. tomorrow). ;-)

    BTW: I've been using DataTables extensively in my cimsPR 2.0 app and you deserve contributions!!!
  • jamjon3jamjon3 Posts: 22Questions: 0Answers: 0
    BTW: I reverted back to the fnUpdate array format but it breaks my object references so my select dropdown column which just reverts back. I'll just move on for now. Just FYI as a use case for you.
  • jamjon3jamjon3 Posts: 22Questions: 0Answers: 0
    I dealt with the fnUpdate by avoiding it and doing a fnDeleteRow and fnAddData...
    [code]
    "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
    $(nRow).unbind('click')
    .click(function (event) {
    if(!($(event.target).is('select#connectionsId',nRow))) {
    if($(nRow).hasClass('row_selected')) {
    $(nRow).removeClass('row_selected');
    connectionSourceDiscardSourceButton.button( "option", "disabled", true );
    } else {
    $(self.connectionSourceDataTable.fnGetNodes( )).each(function() {
    $(this).removeClass('row_selected');
    });
    $(nRow).addClass('row_selected');
    connectionSourceDiscardSourceButton.button( "option", "disabled", false );
    }
    }
    })
    .find('select#connectionsId')
    .change(function() {
    var jsonRequest = {
    recursionIndex: 10,
    source: {
    sourceId : aData.sourceId
    }
    };
    if($(this).val() !== '') {
    var connectionsId = $(this).val();
    $.extend(jsonRequest,{
    connection: {
    connectionsId: connectionsId
    }
    });
    }
    $.ajax({
    url: "/cimsPR/ConnectionServlet",
    title: 'Assigning connection to source',
    data : {
    service : "assignConnectionToSource",
    json: JSON.stringify(jsonRequest)
    },
    success: function(assignConnectionToSourceResponse, textStatus, jqXHR) {
    // Find the this source in the array and update the values
    $.each(connection.sources,function(index, source) {
    if(source.sourceId == aData.sourceId) {
    connection.sources[index] = assignConnectionToSourceResponse.source;
    var isSelected = $(nRow).hasClass('row_selected');
    connectionSourceDataTable.fnDeleteRow(nRow);
    nRow = connectionSourceDataTable.fnGetNodes(connectionSourceDataTable.fnAddData(assignConnectionToSourceResponse.source)[0]);
    if(!isSelected) {
    $(nRow).addClass('row_selected');
    }
    // connectionSourceDataTable.fnUpdate(source, nRow, 0 );
    self.storage.connection.sources = connection.sources;
    return false;
    } else {
    return true;
    }
    });
    }
    });
    });
    return nRow;
    }
    [/code]
  • allanallan Posts: 61,438Questions: 1Answers: 10,052 Site admin
    I've just updated DataTables' fnUpdate method to take either an individual value, an array of values or an object (of the same format as the original data source, if objects are being used). This has been committed and can be picked up from the nightly, or 1.8 beta 3 which I'll release shortly.

    Allan
  • jamjon3jamjon3 Posts: 22Questions: 0Answers: 0
    Thanks again Allan!!!! I'm going to pull that down and give it a shot. The code I produced above produced some unpredictable results in different browsers (not production quality code). In hindsight, I should have just rebuilt the whole table by clearing it but no matter now that fnUpdate will handle an object.
  • jamjon3jamjon3 Posts: 22Questions: 0Answers: 0
    edited May 2011
    Problem. fnUpdate is taking this object....

    [code]
    {
    "source": {
    "sourceId": 7,
    "name": "MANUALENTRY",
    "description": "",
    "connection": {
    "connectionsId": 3,
    "hibernateProperties": "hibernate.current_session_context_class\u003djta\r\nhibernate.show_sql\u003dtrue\r\nhibernate.session_factory_name\u003dcims_datawarehousePU_sf\r\nhibernate.dialect\u003dorg.hibernate.dialect.Oracle10gDialect\r\nhibernate.jdbc.fetch_size\u003d2000\r\nhibernate.transaction.manager_lookup_class\u003dorg.hibernate.transaction.SunONETransactionManagerLookup\r\njta.UserTransaction\u003djava:comp/UserTransaction",
    "jndi": "jdbc/cims_datawarehouse",
    "namedQueries": [

    ]
    }
    }
    }
    [/code]

    but is returning this object from a fnGetData

    [code]
    {
    "sourceId": 7,
    "name": "MANUALENTRY",
    "description": "",
    "null": "Unassigned1 - jdbc/cimsPR2 - jdbc/cims_oasis3 - jdbc/cims_datawarehouse4 - jdbc/cims_alumni5 - jdbc/cims_idcards6 - jdbc/cims_nams7 - jdbc/cims_med_banner8 - jdbc/cims_med_alt_banner9 - jdbc/cims_namsdev10 - jdbc/cims_baggageclaim11 - jdbc/cims_gems12 - jdbc/cims_peopleadmin"
    }
    [/code]

    I'm using a "fnRender" to render the selectbox but it looks like the "connection" object is being destroyed and replaced with one named "null" with the results of the fnRender. The effect this is having and returning the select back to the original selected value before the change event occurred. Not sure what's happening but it looks like the previous rendered column before the select drop down change is replacing the connections object.

    I'm using your latest nightly. Soooo close!!!! Thanks for your patience with me!!!!

    BTW: Here's my fnRender reference for the connections column

    [code]
    { "sTitle": "Connection (Re)Assignment","sClass": "SearchColumn","mDataProp": "null","sDefaultContent":"","fnRender":
    function(oObj) {
    // Build a drop down of Connections
    var connectionSelect = "";
    if(oObj.aData.connection !== undefined) {
    connectionSelect += "Unassigned";
    } else {
    connectionSelect += "Unassigned";
    }
    $.each(connection.connections,function(index,conn) {
    if((oObj.aData.connection !== undefined)?((oObj.aData.connection.connectionsId === conn.connectionsId)?true:false):false) {
    connectionSelect += ["",conn.connectionsId," - ",conn.jndi,""].join("");
    } else {
    connectionSelect += ["",conn.connectionsId," - ",conn.jndi,""].join("");
    }
    });
    connectionSelect += "";
    return connectionSelect;
    }
    }
    [/code]
  • jamjon3jamjon3 Posts: 22Questions: 0Answers: 0
    Tried to turn off rendering but same effect (and slightly messed up the jEditable 's that were empty). This only seems to be a problem when I use fnRender on a field.
  • allanallan Posts: 61,438Questions: 1Answers: 10,052 Site admin
    You've got

    [code]
    "mDataProp": "null"
    [/code]
    which is setting the data property DataTables is using to the string "null" - not null. null !== "null" :-)

    You should have more luck with:

    [code]
    "mDataProp": null
    [/code]
    Allan
  • jamjon3jamjon3 Posts: 22Questions: 0Answers: 0
    THAT WORKED and has a pretty cool implication. If you want the rendered version of the column to come back something like:

    [code]
    { "sTitle": "Connection (Re)Assignment","sClass": "SearchColumn","mDataProp": "connection","sDefaultContent":"","fnRender": and so on...
    [/code]

    Gives you the render mapped to the name specified (here I put "connection")

    [code]
    {"sourceId":7,"name":"MANUALENTRY","description":"","connection":"Unassigned1 - jdbc/cimsPR2 - jdbc/cims_oasis3 - jdbc/
    cims_datawarehouse4 - jdbc/cims_alumni5 - jdbc/cims_idcards6 - jdbc/cims_nams7 - jdbc/cims_med_banner8 - jdbc/
    cims_med_alt_banner9 - jdbc/cims_namsdev10 - jdbc/cims_baggageclaim11 - jdbc/cims_gems12 - jdbc/cims_peopleadmin"}
    [/code]

    And, of course, using null instead of "null" (THANKS for catching that) like:

    [code]
    { "sTitle": "Connection (Re)Assignment","sClass": "SearchColumn","mDataProp": null,"sDefaultContent":"","fnRender": .. and so on
    [/code]

    Gives back the unaltered object perfectly like this just as you suggested (thanks for the help on that!)

    [code]
    {"sourceId":7,"name":"MANUALENTRY","description":"","connection":{"connectionsId":
    3,"hibernateProperties":"hibernate.current_session_context_class=jta\r\nhibernate.show_sql=true\r
    \nhibernate.session_factory_name=cims_datawarehousePU_sf\r\nhibernate.dialect=org.hibernate.dialect.Oracle10gDialect\r
    \nhibernate.jdbc.fetch_size=2000\r
    \nhibernate.transaction.manager_lookup_class=org.hibernate.transaction.SunONETransactionManagerLookup\r
    \njta.UserTransaction=java:comp/UserTransaction","jndi":"jdbc/cims_datawarehouse","namedQueries":[]}}
    [/code]

    Not exactly sure how one might make use of that BUT it IS a cool mechanism that could be useful depending on one's circumstances. Of course, since I'm doing serialization/deserialization on the app side, I'm keeping it all true in structures client-side so I can pass objects back and forth but who knows! Thanks again!
  • jamjon3jamjon3 Posts: 22Questions: 0Answers: 0
    I'd make a friendly suggestion for documentation to ALWAYS use "mDataProp": null when you are ALSO using "fnRender" UNLESS you intend to have the underlying object come back with the rendered value of that property (instead of the raw data) in your object when you retrieve it.

    Pretty fantastic stuff you've created here!
  • allanallan Posts: 61,438Questions: 1Answers: 10,052 Site admin
    Another consideration is that you can use bUseRendered to indicate that DataTables should keep the original data when using fnRender. Quite a few options in this area now :-).

    Good to hear that this is proving to be useful already - I'm using the mDataProp options in some of my own uses of DataTables now as well and finding it very useful! Thanks fir your inout and testing this feature.

    Regards,
    Allan
  • lucasnplucasnp Posts: 18Questions: 0Answers: 0
    I am not sure if this is the right topic. I run into an issue: when I create a new row, can its cells have the same "name" attributes as the existing rows?
  • jamjon3jamjon3 Posts: 22Questions: 0Answers: 0
    edited June 2011
    What's the problem specifically?
  • lucasnplucasnp Posts: 18Questions: 0Answers: 0
    each td tag in my table has a "name" attribute I use to update the database. so when I insert new row, the name attribute is not carried to the new row.

    My work around is to generate an array of name of each td after initiate the table. and on fnDrawBack I loop through the fnGetNodes().childNodes and look for the one without name attribute then replace each with the values in the array.

    I know there must be a better way, i just could not find it :(
  • jamjon3jamjon3 Posts: 22Questions: 0Answers: 0
    I'm not sure if I'm understanding this right but I think you are saying you want set for each row. There's probably better ways to do this but you can try adding on something like this in your datatable setup (if I'm off base, sorry about that):

    [code]
    "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
    var rowNames = [
    "col1",
    "col2",
    "col3"
    ];
    $(nRow).children().each(function(index,nCol) {
    $(nCol).attr("name",rowNames[index]);
    });
    return nRow;
    }

    [/code]
  • lucasnplucasnp Posts: 18Questions: 0Answers: 0
    Yep, that's it. :) it's way better than what I did :)

    [code]
    "fnInitComplete": function(){
    for(i=0; i < this.fnGetNodes(0).childNodes.length; i++)
    {
    f_name_arr[i] = this.fnGetNodes(0).childNodes[i].getAttribute("name");
    }
    },
    "fnDrawCallback": function(){
    for(i=0; i < this.fnGetNodes().length; i++)
    {
    temp_row = this.fnGetNodes(i);
    if(!(temp_row.childNodes(0).getAttribute("name")))
    {
    for(j=0; j < temp_row.childNodes.length; j++)
    {
    temp_row.childNodes[j].setAttribute("name",f_name_arr[j]);
    }
    break;
    }
    }
    fnCreateFilter(this); //refresh filter
    }
    [/code]
This discussion has been closed.