8

DEFAULT
I create ajax datatable, which rows are sometimes filled by json in the end of table: jsfiddle and sometimes in the top of table. It depends of time of ajax response.

RECOMMENDED OUTPUT
I have two input jsons from two different sources and output is this table:

<table>
    <tr><td>1</td><td>2</td><td>3</td></tr>
    <tr><td>1</td><td>2</td><td>3</td></tr>
    <tr><td>1</td><td>2</td><td>3</td></tr>
    ...
    <tr><td>1</td><td>2</td><td>3</td></tr>
    <tr><td>1</td><td>2</td><td>3</td></tr>
    <tr><td>8</td><td>7</td><td>6</td></tr> <!-- inserted row-->
    <tr><td>8</td><td>7</td><td>6</td></tr> <!-- inserted row-->
    <tr><td>8</td><td>7</td><td>6</td></tr> <!-- inserted row-->
    <tr><td>8</td><td>7</td><td>6</td></tr> <!-- inserted row-->
    <tr><td>1</td><td>2</td><td>3</td></tr>
    <tr><td>1</td><td>2</td><td>3</td></tr>
    ...
    <tr><td>1</td><td>2</td><td>3</td></tr>
</table>

Rows from 2. json are inserted in table (created from 1. json) to specific position. This position is constant, lengths of 1. and 2. json data are constant.

FIRST SOLUTION
I have to add first column containing a number and sort the datatable descending by it - jsfiddle. I can hide first column jsfiddle, but I rather use custom function, because it doesn't work in IE8.

var t = $("#tab1").DataTable({
    "ajax": "data1.json",
    columnDefs: [
         { className: "hide", "targets": [ 0 ] },
         ], 
    "columns": [
        { "data": "id"},
        { "data": "cat1"},
        { "data": "cat2"},
        { "data": "cat3"}
    ]
});

$.ajax({
    type: "GET",
    url: "data2.json",
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (response) {
        t.rows.add(response.data); 
        t.draw();
    }
  });

IDEA - CUSTOM FUNCTION
I try to create custom function rows.addinposition(rows, position), but it works as function rows.add().
I copied and modified function rows.add found in jquery.dataTables.js at line 7879, I changed out.push() to out.splice() splice docs.

I know, it is not recommended, better is extend datatables api...

_api_register( 'rows.addinposition()', function ( rows, position ) {
    var newRows = this.iterator( 'table', function ( settings ) {
            var row, i, ien;
            var out = [];

            for ( i=0, ien=rows.length ; i<ien ; i++ ) {
                row = rows[i];

                if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
                    //ROWS.ADD USE OUT.PUSH
                    //out.push( _fnAddTr( settings, row )[0] );
                    //CHANGED TO OUT.SPLICE
                    out.splice( position, 0, _fnAddTr( settings, row )[0] );
                }
                else {
                    out.splice( position, 0, _fnAddData( settings, row ) );
                }
            }
            console.log(out);
            return out;

        }, 1 );

    // Return an Api.rows() extended instance, so rows().nodes() etc can be used
    var modRows = this.rows( -1 );
    modRows.pop();
    modRows.push.apply( modRows, newRows.toArray() );

    return modRows;
} );    

It would be great if you could help me.

I found similar questions:

EDIT
Thank you davidkonrad, but I test it in jsfiddle, and I found 2 problems:

  • ordering is wrong 2.,1., not 1.,2. - I think easy problem
  • sometimes this added rows are on the top of table, sometimes in right position. Randomly. - maybe big problem

I debug it in jsfiddle and its behaviour is very strange:

console.log('rowCount = '+rowCount);

if rows are on the top (bad position) return:

rowCount = 0
rowCount = 1

and for didn't loop, because firebug doesn't show var i.

if they are in good position, return:

rowCount = 5
rowCount = 6

and for looped and var i returned in this example:
1. loop:

i = 5 
i = 4 
i = 3

2.loop:

i = 6 
i = 5 
i = 4 
i = 3

Did i missed something? Why order is strange?

Community
  • 1
  • 1
jezrael
  • 822,522
  • 95
  • 1,334
  • 1,252
  • Can you please explain what are you trying to achieve? Why do you need to insert row at specific position, what is the reasoning behind it? – Gyrocode.com Aug 01 '15 at 03:32
  • I added recommended output to question. – jezrael Aug 01 '15 at 06:40
  • It's still not clear **why** you're trying to do this. Let's [continue the discussion in chat](http://chat.stackoverflow.com/rooms/84885/room-for-gyrocode-com-and-jezrael). – Gyrocode.com Aug 01 '15 at 11:57

2 Answers2

6

You do not need to modify the source code directly, use dataTable.Api.register instead :

jQuery.fn.dataTable.Api.register('row.addByPos()', function(data, index) {     
    var currentPage = this.page();

    //insert the row  
    this.row.add(data);

    //move added row to desired index
    var rowCount = this.data().length-1,
        insertedRow = this.row(rowCount).data(),
        tempRow;

    for (var i=rowCount;i>=index;i--) {
        tempRow = this.row(i-1).data();
        this.row(i).data(tempRow);
        this.row(i-1).data(insertedRow);
    }     

    //refresh the current page
    this.page(currentPage).draw(false);
});

The above function (or plugin) inserts the row, and then "moves" the row up to its desired position simply by swapping content -> read more detailed explanation.
Demo -> http://jsfiddle.net/p4wcfzfe/

Since the plugin adds a function to the general API, the plugin should be declared before initialization of any dataTable using that function.

{ plugin declaration }
var table = $("#example").DataTable();
table.row.addByPos([data], 1);

NB: Your "first solution" should work in IE8 too, try to remove the trailing commas.

Community
  • 1
  • 1
davidkonrad
  • 83,997
  • 17
  • 205
  • 265
  • @jezrael, you are trying to insert multiple new rows at the same time while the function only take one row at a time (if you see the code, it only moves one row from array end to desired position, not multiple rows). You must call `addByPos` for each row -> `response.data.forEach(function(data) { t.row.addByPos(data, 1); })` forked fiddle -> **http://jsfiddle.net/p4wcfzfe/** or alternatively refactor `addByPos` to take more complex datatypes. – davidkonrad Jul 28 '15 at 11:35
  • no, `table.row` should be `this.row`, sry for the typo. – davidkonrad Jul 28 '15 at 11:38
  • @jezrael, have done that. Thank you for accepting the answer! I guess I should have added a fiddle the first time to prevent the typo, in fact the answer was tested in a fiddle -> http://jsfiddle.net/anxw7063/ :( – davidkonrad Jul 28 '15 at 11:46
  • I test it in http://jsfiddle.net/jezrael/p4wcfzfe/1/, I only change position to 3. I found 2. problems: - ordering is wrong (2.,1.), not 1.,2. and sometimes this added rows are on the top of table, sometimes in right position. Randomly :( – jezrael Jul 28 '15 at 13:40
  • This works but only for a row's data it ignores the tr tag's attributes like class, id, etc. Is their a way to do this so it moves the entire "node" instead of just the data? – Kevin P Oct 18 '18 at 18:37
3

SOLUTION

I believe you need to use jQuery $.when function to execute callback when both Ajax calls were successful.

That way you get data always in the same order and there is no need to write functions to insert data at specific position.

Also, if needed, you can manipulate the final data before initializing the data table with it. For example, shown below are just two options, the possibilities are limitless.

To append data from call2 to data from call1:

var data = a1[0].data.concat(a2[0].data);

To insert data from call2 at position 2 of data from call1 (source):

var data = a1[0].data;
data.splice.apply(data, [2, 0].concat(a2[0].data));

DEMO

See example below for code and demonstration.

$(document).ready(function(){
   var call1 = $.ajax({
      url: "https://api.myjson.com/bins/48g56",
      type: "GET",
      dataType: "json",
      contentType: "application/json; charset=utf-8",
   });

   var call2 = $.ajax({
      url: "https://api.myjson.com/bins/1bfa2",
      type: "GET",
      dataType: "json",
      contentType: "application/json; charset=utf-8",
   });
   
   
   // When both Ajax requests were successful
   $.when(call1, call2).done(function(a1, a2){
      // a1 and a2 are arguments resolved for the call1 and call2 ajax requests, respectively.
      // Each argument is an array with the following structure: [ data, statusText, jqXHR ]
     
      // Append data from call2 to data from call1
      // var data = a1[0].data.concat(a2[0].data);
     
      // Insert data from call2 at position 2 of data from call1
      var data = a1[0].data;
      data.splice.apply(data, [2, 0].concat(a2[0].data));
     
      // Initialize data table
      var t = $("#tab1").DataTable({
         data: data,
         columnDefs: [
            { className: "hide", "targets": [ 0 ] },
         ], 
         order: [],
         ordering: false,        
         columns: [
            { "data": "id"},
            { "data": "cat1"},
            { "data": "cat2"},
            { "data": "cat3"}
         ]
      });
   });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://cdn.datatables.net/1.10.7/js/jquery.dataTables.js"></script>
<link href="http://cdn.datatables.net/1.10.7/css/jquery.dataTables.css" rel="stylesheet"/>


<table id="tab1" class='data tab01'>
 <thead>
  <tr>
    <th>id</th>
            <th>cat1</th>
   <th>cat2</th>
   <th>cat3</th>
  </tr>
 </thead>
 <tbody>
 </tbody>
</table>
Community
  • 1
  • 1
Gyrocode.com
  • 57,606
  • 14
  • 150
  • 185
  • Thank you, but ordering is problem, because `"aaSorting": []` is not present in demo. I create this http://jsfiddle.net/7j19hj5s/16/ where first "ordering" column is missing and added rows are unfortunately in the end of table – jezrael Aug 02 '15 at 19:43
  • @jezrael, I forgot to disable ordering in my demo. I [mentioned before](http://chat.stackoverflow.com/transcript/message/24818513#24818513) *that you would need to disable sorting if you want rows to stay in certain position all the time*, and [you said](http://chat.stackoverflow.com/transcript/message/24818529#24818529) that you will disable it. – Gyrocode.com Aug 02 '15 at 20:56
  • @jezrael, you can manipulate results `a1` and `a2` as you wish but important part is that you know that `a1` is a result of first call and `a2` - second. Let me update the answer with details. – Gyrocode.com Aug 02 '15 at 21:07