fnGetPosition should return original data indexes

fnGetPosition should return original data indexes

mimicmimic Posts: 43Questions: 0Answers: 0
edited March 2009 in Bug reports
fnGetPosition should return original data indexes (hidden columns counted in) as using fnGetPosition to get cell position and then fnUpdate to update data is otherwise not possible with hidden columns.

Replies

  • mimicmimic Posts: 43Questions: 0Answers: 0
    Hm, so it seems that it is not possible to manipulate original data and leave to dataTables to rebuild columns made with fnRender.
  • mimicmimic Posts: 43Questions: 0Answers: 0
    So fnGetPosition returns indexes without hidden columns, fnUpdate requires indexes with hidden columns, but updates only visible columns? I think I am missing something ...

    So what would be the best way to hide some columns, display data stored there in some other columns and then from time to time update some of that data in those hidden columns and rebuild those other columns? And of course ... those columns should have event handlers defined and I do not like an idea of defining again and again event handlers on all cells - is there a way to do that progressively only on cells I would change?
  • allanallan Posts: 63,602Questions: 1Answers: 10,486 Site admin
    Hi mimic,

    You are quite right - there is indeed a discrepancy between my two API functions there. The reason for the fnGetPosition() returning the node position is that it makes updating the DOM element much easier - while at the same time the fnUpdate() function needs to update data based on it's position in the internal storage array.

    To address this what I think I will do is to include a little bit more information in the array returned by fnGetPosition(). A third element which is the column index (including hidden columns) would help to address this. Does this sound reasonable?

    With regard to fnRender() for an update - you are quite right - this is a bug and I'll address that in the next release.

    And finally, updating data in hidden columns - again quite right. This is also a bug, it should not be dependant on the visible columns. Rather, the index it takes should include hidden columns as well. I'll also make this API change in the next release (probably at the weekend with these API changes).

    Thanks very much for looking at the fnUpdate() function so closely - it's much appreciated!

    Regards,
    Allan
  • mimicmimic Posts: 43Questions: 0Answers: 0
    The idea to return both indexes is great. In this way user can decide what it needs.

    But I do not understand your argument for current behavior though. If you are searching for position with fnGetPosition you already have the DOM element which you want to find. So if you want to update this DOM element you can do this directly. As using those indexes on data returned by fnGetData again requires indexes with hidden columns included, doesn't it?

    I think the behavior should be as such:

    fnGetPosition returns both indexes, an index in data and an index in DOM table
    fnGetData returns data with hidden columns included, so you can update data directly there and then call fnRebuild to reinitialize everything (fnRedraw should just redraw things, it should not destroy DOM, but fnRebuild would, it would also have a new callback possible), calling fnRebuild would be costly so this way of updating should not be used much
    fnUpdate where you can also update data in hidden columns, it would also rebuild DOM elements, if there is any visible for that data
    fnRebuild to rebuild everything, would take callback
    fnRebuildCell to rebuild just one cell, would take callback

    In this way if you would like to manipulate only DOM you would use fnGetNodes + fnGetPosition (like $(fnGetNodes()[row]).find("td").get(columnWithoutHidden)). Or you could use DOM elements accessed or stored in some other way by yourself. Of course then you have to be careful that those changes will be lost if you change data directly later on. (It is great now that DOM elements are not destroyed on redraw.) (And there is nothing dataTables has to do now to help user who wishes to change DOM - now that it is not destroying user's changes anymore.)

    If you would like to change data directly, you would use fnGetData + fnRebuild, which would be costly. You would also be able to specify a callback to process this newly rebuilded DOM.

    If you would like to update only a small part of data you would use fnUpdate which would change data directly and would update only necessary DOM elements. And callback would then be able to process this new DOM elements. It would be user's obligation to do fnRebuildCell on any cell this new data is depended upon in those cells' fnRender.

    So for example I would use fnUpdate on a hidden column with redraw flag set to false (there would nothing be rebuilded as no cell is connected to that hidden column). And then I would do fnRebuildCell on a displayed cell which uses this hidden column in fnRender. This call also needs a redraw flag as if I would have more cells to rebuild then I would be able to specify false redraw on all except the last cell rebuilding. (Or even better - fnRebuildCell redraw would redraw only the cell which it rebuilt so it would not necessary for user to keep track of this and can use enabled redrawing also on multiple updates at the same time.) (This could also fnUpdate do - redraw only necessary things.)
  • mimicmimic Posts: 43Questions: 0Answers: 0
    edited March 2009
    This is an idea. Maybe we could get rid of all this double data (DOM and data array) thing and use only DOM and http://docs.jquery.com/Internals/jQuery.data to store original data. dataTables would then only need to store filtered and sorted indices. fnRender would be a handy non-default transformation for data to DOM conversion.

    But the question is then what to do with hidden columns. Hmm.
  • allanallan Posts: 63,602Questions: 1Answers: 10,486 Site admin
    I'm afraid I don't really understand your point about what fnRebuild() will do? Do you mean it will basically update the entire table from scratch? Surely you would only want to do this if you had some information which is dependant on other information.

    With regard to removing the need to store the data twice, as I'm sure you know parsing the DOM is very slow, so this would have a huge knock on effect for filtering and sorting. Indeed that is why I used my current method.

    Looking again at fnUpdate - it looks like it does actually update _aData (the internal storage) for hidden columns already - but it (correctly) doesn't update the DOM on the hidden columns since that column has been removed.

    Allan
  • mimicmimic Posts: 43Questions: 0Answers: 0
    edited March 2009
    Yes, fnRebuild would rebuild everything from scratch. But now I was thinking that there is not really a need for this if fnUpdate would call fnRender. So those functions you have defined are enough. Because I can do;

    fnUpdate("data for hidden column 1", row, hidden_column_1, false);
    fnUpdate("data for hidden column 2", row, hidden_column_2, false);
    fnUpdate("new data which will be rendered with data from hidden column 1 and 2", row, visible_column, true);

    So the order of updating data is important. And that fnRender is called if it exists.

    But fnUpdate should take a callback function so that I can assign events to built DOM td element.

    And it does not seem fnUpdate is working correctly with current implementation. If I have two columns somewhere in the middle of the table, i and i + 1, where i is visible and i + 1 is not, if I call:

    oTable.fnUpdate('hidden_column_data', row, i + 1, false);
    oTable.fnUpdate("visible_column_data", row, i, true);

    Two visible columns are updated. One (correctly) corresponding to i, and the next column to that corresponding to i. I think the problem is in _fnColumnIndexToVisible function, which does not return null when called on a hidden column. I think the if clause should be like this:

    if ( i == iMatch )
    {
    if ( oSettings.aoColumns[i].bVisible === true )
    {
    return iColumn;
    }
    else
    {
    return null;
    }
    }

    About storing the data twice, you would not need to parse DOM as I understand. You would only store an array of all tr rows, you would add to those rows data, and you would directly be able to access it. But it is true, it would have been less efficient then it is now. And now that I am thinking this storage on one place would not really benefit anything. (It would also have the same problem as fnGetData had in my other post.) So forget about that.
This discussion has been closed.