Showing posts with label datatables. Show all posts
Showing posts with label datatables. Show all posts

Friday, July 6, 2018

Complex R Shiny input binding issue with datatable

Leave a Comment

I am trying to do something a little bit tricky and I am hoping that someone can help me.

I would like to add selectInput inside a datatable. If I launch the app, I see that the inputs col_1, col_2.. are well connected to the datatable (you can switch to a, b or c)

BUT If I update the dataset (from iris to mtcars) the connection is lost between the inputs and the datatable. Now if you change a selectinput the log doen't show the modification. How can I keep the links?

I made some test using shiny.bindAll() and shiny.unbindAll() without success.

Any Ideas?

Please have a look at the app:

library(shiny) library(DT) library(shinyjs) library(purrr)      ui <- fluidPage(       selectInput("data","choose data",choices = c("iris","mtcars")),       DT::DTOutput("tableau"),       verbatimTextOutput("log")     )      server <- function(input, output, session) {       dataset <- reactive({         switch (input$data,           "iris" = iris,           "mtcars" = mtcars         )       })        output$tableau <- DT::renderDT({         col_names<-           seq_along(dataset()) %>%          map(~selectInput(           inputId = paste0("col_",.x),           label = NULL,            choices = c("a","b","c"))) %>%            map(as.character)          DT::datatable(dataset(),                   options = list(ordering = FALSE,                            preDrawCallback = JS("function() {                                                Shiny.unbindAll(this.api().table().node()); }"),                          drawCallback = JS("function() { Shiny.bindAll(this.api().table().node());                          }")           ),           colnames = col_names,            escape = FALSE                  )        })       output$log <- renderPrint({         lst <- reactiveValuesToList(input)         lst[order(names(lst))]       })      }      shinyApp(ui, server) 

1 Answers

Answers 1

Understanding your challenge:

In order to identify your challenge at hand you have to know two things.

  1. If a datatable is refreshed it will be "deleted" and build from scratch (not 100% sure here, i think i read it somewhere).
  2. Keep in mind that you are building a html page essentially.

selectInput()is just a wrapper for html code. If you type selectInput("a", "b", "c") in the console it will return:

<div class="form-group shiny-input-container">   <label class="control-label" for="a">b</label>   <div>     <select id="a"><option value="c" selected>c</option></select>     <script type="application/json" data-for="a" data-nonempty="">{}</script>   </div> </div> 

Note that you are building <select id="a">, a select with id="a". So if we assume 1) is correct after refresh you attempt to build another html element : <select id="a"> with an existing id. That is not supposed to work: Can multiple different HTML elements have the same ID if they're different elements?. (Assuming my assumption 1) holds true ;))

Solving your challenge:

On first sight pretty simple: Just ensure the id you use is unique within the created html document.

The very quick and dirty way would be to replace:

inputId = paste0("col_",.x) 

with something like: inputId = paste0("col_", 1:nc, "-", sample(1:9999, nc)).

But that would be difficult to use afterwards for you.

Longer way:

So you could use some kind of memory

  1. Which ids you already used.
  2. Which ones are your current ids in use.

You can use

  global <- reactiveValues(oldId = c(), currentId = c()) 

for that.

An idea to filter out the old used ids and to extract the current ones could be this:

    lst <- reactiveValuesToList(input)     lst <- lst[setdiff(names(lst), global$oldId)]     inp <- grepl("col_", names(lst))     names(lst)[inp] <- sapply(sapply(names(lst)[inp], strsplit, "-"), "[", 1) 

Reproducible example would read:

library(shiny) library(DT) library(shinyjs) library(purrr)  ui <- fluidPage(   selectInput("data","choose data",choices = c("iris","mtcars")),   dataTableOutput("tableau"),   verbatimTextOutput("log") )  server <- function(input, output, session) {    global <- reactiveValues(oldId = c(), currentId = c())    dataset <- reactive({     switch (input$data,             "iris" = iris,             "mtcars" = mtcars     )   })    output$tableau <- renderDataTable({     isolate({       global$oldId <- c(global$oldId, global$currentId)       nc <- ncol(dataset())       global$currentId <- paste0("col_", 1:nc, "-", sample(setdiff(1:9999, global$oldId), nc))        col_names <-         seq_along(dataset()) %>%          map(~selectInput(           inputId = global$currentId[.x],           label = NULL,            choices = c("a","b","c"))) %>%          map(as.character)     })         DT::datatable(dataset(),                   options = list(ordering = FALSE,                                   preDrawCallback = JS("function() {                                                       Shiny.unbindAll(this.api().table().node()); }"),                                  drawCallback = JS("function() { Shiny.bindAll(this.api().table().node()); }")           ),           colnames = col_names,            escape = FALSE              )  })   output$log <- renderPrint({     lst <- reactiveValuesToList(input)     lst <- lst[setdiff(names(lst), global$oldId)]     inp <- grepl("col_", names(lst))     names(lst)[inp] <- sapply(sapply(names(lst)[inp], strsplit, "-"), "[", 1)     lst[order(names(lst))]   })  }  shinyApp(ui, server) 
Read More

Thursday, March 1, 2018

jQuery Datatables - footerCallback sum columns, issues with table total

Leave a Comment

ive created a function that I can call on columns that I wish to sum up using the below. however the total (table total) entry for column 9 is always zero. the page total seems to work. and the page total and table total for column 9 works also.

"footerCallback": function ( row, data, start, end, display ) {             var api = this.api(), data;             // Remove the formatting to get integer data for summation             var intVal = function ( i ) {                 return typeof i === 'string' ?                     i.replace(/[\£,]/g, '')*1 :                     typeof i === 'number' ?                         i : 0;             };             var column_sum = function (col) {                 // Total over all pages                 total = api                     .column(col)                     .data()                     .reduce( function (a, b) {                         return intVal(a) + intVal(b);                     }, 0 );                 // Total over this page                 pageTotal = api                     .column(col, { page: 'current'} )                     .data()                     .reduce( function (a, b) {                         return intVal(a) + intVal(b);                     }, 0 );                 return accounting.formatMoney(pageTotal) +' ('+ accounting.formatMoney(total) +' total)'             };             // Update footer             $( api.column(6).footer()).html(                 column_sum(6)             );             $( api.column(9).footer()).html(                 column_sum(9)             );         } 

EDIT

I have added some sanitised data. currently the page total works for the first column and second columns.

The all pages total does not work. i.e each time I filter by the column header I should see the total across each page

<table width="100%" class="table table-striped table-bordered table-hover dataTable no-footer dtr-inline" id="circuit_list"  role="grid" style="width: 100%;">     <thead>         <tr>             <th>Info</th>             <th>Type</th>             <th>Cost PM</th>             <th>Term</th>             <th>Remaining Term</th>             <th>Remaining Cost</th>         </tr>     </thead>     <tbody>         <tr>             <td>                 <a href="/circuits/edit/238/1/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>Fibre</td>             <td>£950.00</td>             <td>12</td>             <td>0</td>             <td>£0.00</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/238/2/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>Fibre</td>             <td>£950.00</td>             <td>12</td>             <td>0</td>             <td>£0.00</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/333/101/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>MPLS</td>             <td>£1791.33</td>             <td>12</td>             <td>11</td>             <td>£19,704.63</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/334/101/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>MPLS</td>             <td>£100.00</td>             <td>12</td>             <td>11</td>             <td>£1,100.00</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/235/1/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>MPLS</td>             <td>£593.33</td>             <td>36</td>             <td>15</td>             <td>£8,899.95</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/317/82/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>Fibre</td>             <td>£103.00</td>             <td>3</td>             <td>0</td>             <td>£0.00</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/229/2/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>MPLS</td>             <td>£373.33</td>             <td>36</td>             <td>11</td>             <td>£4,106.63</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/233/1/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>DSL</td>             <td>£1837.66</td>             <td>60</td>             <td>6</td>             <td>£11,025.96</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/234/1/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>DSL</td>             <td>£373.34</td>             <td>36</td>             <td>15</td>             <td>£5,600.10</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/243/5/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>DSL</td>             <td>£373.34</td>             <td>36</td>             <td>15</td>             <td>£5,600.10</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/244/4/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>MPLS</td>             <td>£373.34</td>             <td>36</td>             <td>12</td>             <td>£4,480.08</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/324/83/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>4G</td>             <td>£103.00</td>             <td>3</td>             <td>0</td>             <td>£0.00</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/2/6/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>4G</td>             <td>£41.50</td>             <td>12</td>             <td>0</td>             <td>0.00</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/57/18/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>4G</td>             <td>£45.00</td>             <td>12</td>             <td>0</td>             <td>£0.00</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/113/35/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>Fibre</td>             <td>£45.00</td>             <td>12</td>             <td>0</td>             <td>£0.00</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/218/71/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>4G</td>             <td>£57.00</td>             <td>12</td>             <td>0</td>             <td>£0.00</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/264/71/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>MPLS</td>             <td>£45.00</td>             <td>12</td>             <td>0</td>             <td>£0.00</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/269/61/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>DSL</td>             <td>£45.00</td>             <td>12</td>             <td>0</td>             <td>£0.00</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/300/85/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>4G</td>             <td>£30.00</td>             <td>12</td>             <td>&nbsp;</td>             <td>&nbsp;</td>         </tr>         <tr>             <td>                 <a href="/circuits/edit/307/76/all_cl" class="btn btn-primary btn-circle">                     <i class="fa fa-list"></i>                 </a>             </td>             <td>4G</td>             <td>£45.00</td>             <td>12</td>             <td>6</td>             <td>270.00</td>         </tr>     </tbody> </table> 

1 Answers

Answers 1

Most probably in one or more of the cells for column 9, the value there fails to convert to a number and you are getting a NaN returned by intVal function.

There are 2 issues in intVal:

  1. line i.replace(/[\£,]/g, '')*1 can return NaN
  2. typeof i === 'number' can be true for NaN

From what it seems, intVal is trying to check for this, but the logic is wrong. change the intVal to:

var intVal = function ( i ) {     if(typeof i === 'string') {          i = i.replace(/[\£,]/g, '')*1;    }    // check if you got a valid number.    if (Number.isNaN(i)) {          return 0;    }    return i; }; 

If the filtered total is needed, use:

total = api.column(col, {"filter": "applied"})  

or

total = api.column(col, {"search": "applied"}) 
Read More

Tuesday, February 20, 2018

Paging number list alignment in datatable

Leave a Comment

I am having problems aligning paging numbers in datatables, below is the code.

Datatables library is used to dynamicaly generate a table which includes a paginate and search functionality. I customized the paginate numbering with CSS however the alignment seem to be off the grid.

.dataTables_paginate a {     color: black;     float: left;     padding: 8px 16px;     text-decoration: none;     transition: background-color .3s; }  .dataTables_paginate a.active {     background-color: #4CAF50;     color: white; }  .dataTables_paginate a:hover:not(.active) {background-color: #ddd;} 

Paging

The paging is not aligning to the grid.

Datatable EJS

<h2><% var projectlist = JSON.parse(data); %></h2> <table id="example" class="table table-striped table-bordered dataTable" cellspacing="0" width="100%">   <thead>     <tr>       <th scope="col">#</th>       <th scope="col">CSI ID</th>       <th scope="col">App Name</th>       <th scope="col">Status</th>     </tr>   </thead>   <tbody>      <!-- get projects array from the data property --> <% var counter = 0; %> <% var evale = 'CSI:'; %>  <% for (var key in projectlist) { %>    <% if (projectlist.hasOwnProperty(key)) { %>     <% var csiid = projectlist[key].name.substring(projectlist[key].name.lastIndexOf(":")+1,projectlist[key].name.lastIndexOf("]")); %>     <% if (projectlist[key].name.match(evale)) { %>     <% counter = counter + 1; %>     <tr>     <td><%= counter %></td>     <td><%= csiid %></td>     <td><%= projectlist[key].name.replace(/\[.*?\]\s?/g, '') %></td>      <td>TESTED</td>     </tr>   <% } %>   <% } %>    <% } %>     </tbody> </table> 

Paginate runtime HTML generated by datatables.js

<div class="dataTables_paginate paging_simple_numbers" id="example_paginate">     <a class="paginate_button previous disabled" aria-controls="example" data-dt-idx="0" tabindex="0" id="example_previous">Previous</a>     <span>         <a class="paginate_button current" aria-controls="example" data-dt-idx="1" tabindex="0">1</a>         <a class="paginate_button " aria-controls="example" data-dt-idx="2" tabindex="0">2</a>         <a class="paginate_button " aria-controls="example" data-dt-idx="3" tabindex="0">3</a>         <a class="paginate_button " aria-controls="example" data-dt-idx="4" tabindex="0">4</a>         <a class="paginate_button " aria-controls="example" data-dt-idx="5" tabindex="0">5</a>         <span class="ellipsis">…</span>         <a class="paginate_button " aria-controls="example" data-dt-idx="6" tabindex="0">33</a>     </span>     <a class="paginate_button next" aria-controls="example" data-dt-idx="7" tabindex="0" id="example_next">Next</a> </div> 

3 Answers

Answers 1

you can easily do that by using the below css:

.dataTables_paginate{ display:flex; align-items:center; } .dataTables_paginate a{ padding:0 10px; } 

Display flex will wrap all elements in single row. Align Items center will position the elements vertically center.

Answers 2

Your "clear example" works great.

enter image description here

So I think some of needed styles was declarated somewhere with higher priority.

If it's not possible to remove other declaration, add !important to float. And add display to be sure.

... .dataTables_paginate a {     color: black;     display: block !important;     float: left !important;     padding: 8px 16px;     text-decoration: none;     transition: background-color .3s;  }  ... 

Of course it'll work only if your CSS has connected.

Answers 3

.dataTables_paginate a {      color: black;      float: left;      padding: 8px 16px;      text-decoration: none;      transition: background-color .3s;  }    .dataTables_paginate a.active {      background-color: #4CAF50;      color: white;  }    .dataTables_paginate a:hover:not(.active) {background-color: #ddd;}
<div class="dataTables_paginate paging_simple_numbers" id="example_paginate">      <a class="paginate_button previous disabled" aria-controls="example" data-dt-idx="0" tabindex="0" id="example_previous">Previous</a>      <span>          <a class="paginate_button current" aria-controls="example" data-dt-idx="1" tabindex="0">1</a>          <a class="paginate_button " aria-controls="example" data-dt-idx="2" tabindex="0">2</a>          <a class="paginate_button " aria-controls="example" data-dt-idx="3" tabindex="0">3</a>          <a class="paginate_button " aria-controls="example" data-dt-idx="4" tabindex="0">4</a>          <a class="paginate_button " aria-controls="example" data-dt-idx="5" tabindex="0">5</a>          <span class="ellipsis">…</span>          <a class="paginate_button " aria-controls="example" data-dt-idx="6" tabindex="0">33</a>      </span>      <a class="paginate_button next" aria-controls="example" data-dt-idx="7" tabindex="0" id="example_next">Next</a>  </div>

This is yours. I works perfectly. Check in html file and make sure that you link to css file correctly. Maybe you indicate wrong path to css file.

Read More

Friday, September 22, 2017

Date range and Age range filter on datatable

Leave a Comment

I am trying to implement Daterange and age range filter for datatable.

I have successfully implement age filter. Here is fiddle: http://jsfiddle.net/7y8n0wLj/26/

Here is jquery

$.fn.dataTable.ext.search.push(function (settings, data, dataIndex) {         if ($('#range').val().indexOf("+")>=0){             var number=$('#range').val().slice(0,-1);             //alert(number);             return parseInt(data[1]) > parseInt(number || data[1]);         }else if ($('#range').val().indexOf("-")>=0){             var number=$('#range').val().split("-");             //alert(number[0]);             //alert(number[1]);             return parseInt(data[1]) >= parseInt(number[0] || data[1])                     && parseInt(data[1]) <= parseInt(number[1] || data[1]);         }     });     $('#range').on('change',table.draw); 

But when i am trying to implement Daterange and age range to no avail Here is fiddle: http://jsfiddle.net/evcfespn/176/

$.fn.dataTableExt.afnFiltering.push( function( oSettings, aData, iDataIndex ) {      var grab_daterange = $("#date_range").val();     var give_results_daterange = grab_daterange.split(" to ");     var filterstart = give_results_daterange[0];     var filterend = give_results_daterange[1];     var iStartDateCol = 5; //using column 2 in this instance     var iEndDateCol = 5;     var tabledatestart = aData[iStartDateCol];     var tabledateend= aData[iEndDateCol];      if ( filterstart === "" && filterend === "" )     {         return true;     }     else if ((moment(filterstart).isSame(tabledatestart) || moment(filterstart).isBefore(tabledatestart)) && filterend === "")     {         return true;     }     else if ((moment(filterstart).isSame(tabledatestart) || moment(filterstart).isAfter(tabledatestart)) && filterstart === "")     {         return true;     }     else if ((moment(filterstart).isSame(tabledatestart) || moment(filterstart).isBefore(tabledatestart)) && (moment(filterend).isSame(tabledateend) || moment(filterend).isAfter(tabledateend)))     {         return true;     }     return false; });   $.fn.dataTable.ext.search.push(function (settings, data, dataIndex) {         if ($('#range').val().indexOf("+")>=0){             var number=$('#range').val().slice(0,-1);             //alert(number);             return parseInt(data[3]) > parseInt(number || data[3]);         }else if ($('#range').val().indexOf("-")>=0){             var number=$('#range').val().split("-");             //alert(number[0]);             //alert(number[1]);             return parseInt(data[3]) >= parseInt(number[0] || data[3])                     && parseInt(data[3]) <= parseInt(number[1] || data[3]);         }     }); $('#range').on('change',table.draw); 

Please help.

2 Answers

Answers 1

I'd apply both criteria in your search extension:

$.fn.dataTable.ext.search.push(function(settings, data, dataIndex) {    var fromAge, toAge, inEmpAgeRange, inEmpStartingDateRange;    var empAge = parseInt(data[3]);   var empStartDate = Date.parse(data[4]);    if ($('#range').val().indexOf("+") >= 0) {     fromAge = parseInt($('#range').val().slice(0, -1));     toAge = null;   } else if ($('#range').val().indexOf("-") >= 0) {     var ageRange = $('#range').val().split("-");     fromAge = parseInt(ageRange[0]);     toAge = parseInt(ageRange[1]);   }    inEmpAgeRange = (empAge >= fromAge || empAge) &&     toAge !== null ? (empAge <= (toAge || empAge)) : true;    inEmpStartingDateRange = (dateRangeStart && dateRangeEnd) ?     (moment(empStartDate).isSameOrAfter(dateRangeStart) &&      moment(empStartDate).isSameOrBefore(dateRangeEnd)) : true;    return inEmpAgeRange && inEmpStartingDateRange; }); 

... with setting the values of dateRangeStart and dateRangeEnd earlier in the picker event handlers:

$("#date_range").on('apply.daterangepicker', function(ev, picker) {   dateRangeStart = picker.startDate;   dateRangeEnd = picker.endDate;   $(this).val(dateRangeStart.format('YYYY-MM-DD') + ' to ' + dateRangeEnd.format('YYYY-MM-DD'));   table.draw(); });  $("#date_range").on('cancel.daterangepicker', function(ev, picker) {   dateRangeStart = dateRangeEnd = null;   $(this).val('');   table.draw(); }); 

Updated demo: http://jsfiddle.net/1rr3qpjx/2/

Answers 2

change

var iStartDateCol = 5; //using column 2 in this instance var iEndDateCol = 5; 

to

var iStartDateCol = 4; //using column 2 in this instance var iEndDateCol = 4 

your dates are in fourth column of aData

Read More

Tuesday, September 5, 2017

Datatable vs Angular UI Grid vs Slick Grid vs Ag-Grid

Leave a Comment

I saw there are several flavours of grid. People recommends to use Angular UI Grid when the records are huge instead of Datatables.

I think the data table is populating each row 1 by 1 and causing the performance issue.

Is it not possible to fix the Data table performance issue similar to other grids?

How the angular UI grid works internally or other grids handles differently then the Data tables?

Thanks.

1 Answers

Answers 1

For reference, these are the sites:ag-Grid,ui-grid,slick-grid

we have More Info

and

DataTables Table plug-in for jQuery

DataTables is a plug-in for the jQuery Javascript library. It is a highly flexible tool, based upon the foundations of progressive enhancement, and will add advanced interaction controls to any HTML table.

Data Table

and

JavaScript Open-Source Spreadsheets and Data Grids

Read More

Thursday, July 6, 2017

datatables: how to catch error when using custom ajax function?

Leave a Comment

While using datatables I need to use a custom ajax-function.

The canonical example as found here is as follows:

$('#example').dataTable( {   "ajax": function (data, callback, settings) {     //some async processing happening here     //In the end call the callback.      //However, this callback only accepts a success state     // instead of the usual cb(err, resp) signature.      //This raises the question how to let Datatables know there's an error.     const err = new Error("some contrived error");       //This doesn't work, datatables doesn't signal an actual error     //which can be surfaced to the client. Instead it complains     //the response doesn't have a 'data'-object which it needs     //to correctly create the table. In other words, datatables     //thinks that the passed err-object is an actual correct response.       //Question: so how to actually let datatables know there's an actual error?     callback(err);   } } ); 

However, I don't see a way to let datatables know that an ajax-error occurred.

How to do this?

1 Answers

Answers 1

After trying a few different methods, I think your best bet will be to call the callback function with your data on a success and call callback with empty data on a failure. If there is an error, you can set the text of the .dataTables_empty row to the text of your error message, so it will display in the table. Here's how it would work, and what the code would look like:

Important Note - Make sure to set the .dataTables_empty text after you call the callback, because the callback will set it back (which is actually nice because then you don't have to reset it yourself on each data load)

$('#example').dataTable( {    "columns": [      {"data": "col1"},      {"data": "col2"},      {"data": "col3"},    ],    "ajax": function (data, callback, settings) {      // simulate ajax call with successful data retreival      var myAjaxCall = new Promise(function (resolve, reject) {        $(".dataTables_empty").text("Loading...");        setTimeout(function () {          // `callback()` expects an object with a data property whose value is either           // an array of arrays or an array of objects. Must be in this format          // or you get errors.          var ajaxData = {"data": [            {"col1": "1.1", "col2": "1.2", "col3": "1.3"},            {"col1": "2.1", "col2": "2.2", "col3": "2.3"},            {"col1": "3.1", "col2": "3.2", "col3": "3.3"}          ]};          resolve(ajaxData);        }, 1500);      });            myAjaxCall.then(function resolveCallback(data) {        // render data returned from ajax call        callback(data);      }, function rejectCallback(err) {        callback({data: []});        $(".dataTables_empty").text(err);       });    }  });    $('#example2').dataTable( {    "columns": [      {"data": "col1"},      {"data": "col2"},      {"data": "col3"},    ],    "ajax": function (data, callback, settings) {      // simulate unsuccessful ajax call      var myAjaxCall2 = new Promise(function (resolve, reject) {        $(".dataTables_empty").text("Loading...");        setTimeout(function () {          // reject promise with error message          reject("Something went terribly wrong!");        }, 1500);      });            myAjaxCall2.then(function resolveCallback(data) {        callback(data);      }, function rejectCallback(err) {        // render table with no results        callback({data: []});        // set dataTables empty message text to error message        $(".dataTables_empty").text(err);       });    }  });
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>  <link rel="stylesheet" href="https://cdn.datatables.net/1.10.15/css/jquery.dataTables.min.css" />  <script src="https://cdn.datatables.net/1.10.15/js/jquery.dataTables.min.js"></script>  <h1>Success</h1>  <table id="example">    <thead>      <tr>        <th>Col 1</th>        <th>Col 2</th>        <th>Col 3</th>      </tr>    </thead>    <tbody>    </tbody>  </table>  <h1>Error</h1>  <table id="example2">    <thead>      <tr>        <th>Col 1</th>        <th>Col 2</th>        <th>Col 3</th>      </tr>    </thead>    <tbody>    </tbody>  </table>

Read More

Friday, April 28, 2017

How to bind data using angular js and datatable with extra row and column

Leave a Comment

Hello I am creating one application using angularjs and ASP.NET MVC with datatable js.

I have implemented table showing data using datatable with angular js by help of this article.

But I want to bind the data using same functionality with column names statically in html like:

In article author has done work using:

<table id="entry-grid" datatable="" dt-options="dtOptions"         dt-columns="dtColumns" class="table table-hover"> </table> 

but I want to do it like this by using above same functionality using ng-repeat as per my data:

<table id="tblusers" class="table table-bordered table-striped table-condensed datatable">   <thead>     <tr>       <th width="2%"></th>       <th>User Name</th>       <th>Email</th>       <th>LoginID</th>       <th>Location Name</th>       <th>Role</th>       <th width="7%" class="center-text">Active</th>     </tr>   </thead>   <tbody>     <tr ng-repeat="user in Users">       <td><a href="#" ng-click="DeleteUser(user)"><span class="icon-trash"></span></a></td>       <td><a class="ahyperlink" href="#" ng-click="EditUser(user)">{{user.UserFirstName}} {{user.UserLastName}}</a></td>       <td>{{user.UserEmail}}</td>       <td>{{user.LoginID}}</td>       <td>{{user.LocationName}}</td>       <td>{{user.RoleName}}</td>       <td class="center-text" ng-if="user.IsActive == true"><span class="icon-check2"></span></td>       <td class="center-text" ng-if="user.IsActive == false"><span class="icon-close"></span></td>     </tr>   </tbody> </table> 

I also want to add new column inside the table using the same functionality on button click Add New Record.

Is it possible?

If yes how it can be possible it will be nice and thanks in advance if anyone show me in jsfiddle or any editor.

Please DOWNLOAD source code created in Visual Studio Editor for demo

2 Answers

Answers 1

You can use as davidkonrad suggest the link in the comment just like below structure:

HTML:

<table id="entry-grid" datatable="ng" class="table table-hover">             <thead>                 <tr>                     <th>                         CustomerId                     </th>                     <th>Company Name </th>                     <th>Contact Name</th>                     <th>                         Phone                     </th>                     <th>                         City                     </th>                 </tr>             </thead>             <tbody>                 <tr ng-repeat="c in Customers">                     <td>{{c.CustomerID}}</td>                     <td>{{c.CompanyName}}</td>                     <td>{{c.ContactName}}</td>                     <td>{{c.Phone}}</td>\                     <td>{{c.City}}</td>                 </tr>             </tbody>         </table> 

Create controller in angular like this:

var app = angular.module('MyApp1', ['datatables']); app.controller('homeCtrl', ['$scope', 'HomeService',     function ($scope, homeService) {          $scope.GetCustomers = function () {             homeService.GetCustomers()                 .then(                 function (response) {                     debugger;                     $scope.Customers = response.data;                 });         }          $scope.GetCustomers();     }]) 

Service:

app.service('HomeService', ["$http", "$q", function ($http, $q) {      this.GetCustomers = function () {         debugger;         var request = $http({             method: "Get",             url: "/home/getdata"         });         return request;     } }]); 

Answers 2

Instruct angular-dataTables to use the "angular way" by datatable="ng" :

<table id="entry-grid"     datatable="ng"     dt-options="dtOptions"     dt-columns="dtColumns"     class="table table-hover"> </table>  

Then change dtColumns to address column indexes rather than JSON entries:

$scope.dtColumns = [    DTColumnBuilder.newColumn(0).withTitle('').withOption('width', '2%'),    DTColumnBuilder.newColumn(1).withTitle('User Name'),    DTColumnBuilder.newColumn(2).withTitle('Email'),    DTColumnBuilder.newColumn(3).withTitle('LoginID'),    DTColumnBuilder.newColumn(4).withTitle('Location Name'),    DTColumnBuilder.newColumn(5).withTitle('Role Name'),    DTColumnBuilder.newColumn(6).withTitle('Active').withOption('width', '7%')  ]; 

You can skip the <thead> section entirely if you do as above. Finally I would reduce the two last redundant <td>'s to one :

<td class="center-text">   <span ng-show="user.IsActive == true" class="icon-check2"></span>   <span ng-show="user.IsActive == false" class="icon-close"></span> </td> 
Read More

Sunday, February 5, 2017

How to export search criteria to excel/csv in Jquery Datatable

Leave a Comment

I have used Jquery data table for exporting search result to EXCEL and CSV as shown below :

EmployeeList.html

    <form name="officeForm" id="officeForm" method="post" action="EmployeeList.action">             <div class="pull-right">                     <button class="btn btn-primary-outline btn-sm" type="submit">Search</button>              </div>                <table class="table table-form">             <tbody>                 <tr>                      <td class="control-label">Office</td>                     <td>                         <select id="officeId" name="office">                             <option value="0">ALL</option>                             <option value="108">Bangalore</option>                             <option value="109">Mumbai</option>                             <option value="110">Pune</option>                                                     </select>                                   </td>                               </tr>                   <tr>                      <td class="control-label">Department</td>                     <td>                         <select id="departmentId" name="department">                             <option value="0">ALL</option>                             <option value="118">IT</option>                             <option value="119">HR</option>                             <option value="120">Operations</option> </select>                               </td>                      </tr>                   </tbody>              </table>        </form>      <div class="content-wrapper">             <table class="table table-hover" id="employee-grid" >                 <thead>                     <tr>                         <th>Employee Id</th>                         <th>Name</th>                         <th>Department</th>                         <th>Joined date</th>                     </tr>                 </thead>             </table>     </div> 

Employee.js

var dt = $("#employee-grid").DataTable({             "scrollY": "500px","scrollCollapse":true,"paging":false,"bSortCellsTop": true,             data : [],             "columns" : [{"data":"Id"}, {"data":"name"}, {"data":"department"},{"data":"joinedDate"}]          });    $("#officeForm").submit(function(event){     event.preventDefault();     var $form = $(this);     data = $form.serializeArray();     url = $form.attr("action");      var posting = $.post(url,data);     posting.done(function(dataset){         dt.clear();         dt.rows.add(dataset.searchResults.EMPLOYEE_LIST).draw();                  if(dataset.searchResults.EMPLOYEE_LIST != null && dataset.searchResults.EMPLOYEE_LIST.length != 0)                  {                     new $.fn.dataTable.Buttons( dt, {                         buttons: [                            {                                 extend: 'excelHtml5',                                 filename:'EmployeeList'                            },                                {                                 extend: 'csvHtml5',                                 filename:'EmployeeList'                            }                         ]                     });                      dt.buttons( 0, null ).container().prependTo(                             dt.table().container()                     );                 }  }); 

Here, only the data table rows will be exported to excel/csv.
I have a requirement to export search options(office and department) also to excel/csv.
How to export search options also to excel/csv.

1 Answers

Answers 1

I hope this will help the others too.

  1. save text of selected officeId
  2. save text of selected departemenId
  3. save value from datatables search input
  4. use cusomize option for each button
  5. [easy because this is only text] for csvhtml5 we only need "\n" as ENTER new row, then add them before created dt CSV element
  6. [hard because this is OFFICE XML] for excelhtml5 we need to add OFFICE XML before created dt XML element. The hard point is we need to know first what is OFFICE XML and how to create OFFICE XML manually

here we goes

replace

buttons: [    {         extend: 'excelHtml5',         filename:'EmployeeList'    },        {         extend: 'csvHtml5',         filename:'EmployeeList'    } ] 

into this

buttons: [              {                 extend: 'csvHtml5',                 filename:'EmployeeList',                 customize: function( csv ) {                     var office = $('#officeId :selected').text();                     var department = $('#officeId :selected').text();                     var search = $('.dataTables_filter input').val();                     return "Office: "+ office +"\n"+"Department: "+department+"\n"+"Search Keyword: "+search+"\n\n"+  csv;                 }             },             {                 extend: 'excelHtml5',                 filename:'EmployeeList',                 customize: function( xlsx ) {                     var office = $('#officeId :selected').text();                     var department = $('#officeId :selected').text();                     var search = $('.dataTables_filter input').val();                     var search = $('.dataTables_filter input').val();                     var sheet = xlsx.xl.worksheets['sheet1.xml'];                     var downrows = 4; //number of rows for heading                     var clRow = $('row', sheet);                     //update Row                     clRow.each(function () {                         var attr = $(this).attr('r');                         var ind = parseInt(attr);                         ind = ind + downrows;                         $(this).attr("r",ind);                     });                      // Update  row > c                     $('row c ', sheet).each(function () {                         var attr = $(this).attr('r');                         var pre = attr.substring(0, 1);                         var ind = parseInt(attr.substring(1, attr.length));                         ind = ind + downrows;                         $(this).attr("r", pre + ind);                     });                      function Addrow(index,data) {                         msg='<row r="'+index+'">'                         for(i=0;i<data.length;i++){                             var key=data[i].k;                             var value=data[i].v;                             msg += '<c t="inlineStr" r="' + key + index + '" s="0">';                             msg += '<is>';                             msg +=  '<t>'+value+'</t>';                             msg+=  '</is>';                             msg+='</c>';                         }                         msg += '</row>';                         return msg;                     }                      //insert                     var newline = Addrow(1, [{ k: 'A', v: 'Office: ' + office}]);                     newline += Addrow(2, [{ k: 'A', v: 'Department: ' + department}]);                     newline += Addrow(3, [{ k: 'A', v: 'Search Keyword: ' + search}]);                      sheet.childNodes[0].childNodes[1].innerHTML = newline + sheet.childNodes[0].childNodes[1].innerHTML;                 }             }          ]     

DEMO : https://output.jsbin.com/teyupav

PASTEBIN : http://pastebin.com/ZGt61DCT

Thanks to AugustLEE, J e Harms (member) and Alan (site admin) from datatables.net forum

REFERENCE:

https://datatables.net/extensions/buttons/examples/initialisation/export.html

https://datatables.net/reference/button/excelHtml5

https://datatables.net/reference/api/buttons.exportData()

CSV export

https://datatables.net/forums/discussion/38275

EXCELHTML5 export

https://datatables.net/forums/discussion/39707

https://datatables.net/forums/discussion/36045/excel-export-add-rows-and-data

UPDATE 1: Fix innerHTML problem from safari and IE8 below

this fix is reference from Raghul in same datatables thread https://datatables.net//forums/discussion/comment/103911/#Comment_103911

REPLACE

function Addrow(index,data) {         msg='<row r="'+index+'">'         for(i=0;i<data.length;i++){             var key=data[i].k;             var value=data[i].v;             msg += '<c t="inlineStr" r="' + key + index + '" s="0">';             msg += '<is>';             msg +=  '<t>'+value+'</t>';             msg+=  '</is>';             msg+='</c>';         }         msg += '</row>';         return msg;     }                       //insert                     var newline = Addrow(1, [{ k: 'A', v: 'Office: ' + office}]);                     newline += Addrow(2, [{ k: 'A', v: 'Department: ' + department}]);                     newline += Addrow(3, [{ k: 'A', v: 'Search Keyword: ' + search}]);                      sheet.childNodes[0].childNodes[1].innerHTML = newline + sheet.childNodes[0].childNodes[1].innerHTML; 

INTO

function Addrow(index, data) {                     var row = sheet.createElement('row');                     row.setAttribute("r", index);                                      for (i = 0; i < data.length; i++) {                            var key = data[i].key;                            var value = data[i].value;                             var c  = sheet.createElement('c');                            c.setAttribute("t", "inlineStr");                            c.setAttribute("s", "0");                             c.setAttribute("r", key + index);                             var is = sheet.createElement('is');                            var t = sheet.createElement('t');                            var text = sheet.createTextNode(value)                             t.appendChild(text);                                                                  is.appendChild(t);                            c.appendChild(is);                             row.appendChild(c);                                                                                                                                                 }                         return row;                    }                      var r1 = Addrow(1, [{ key: 'A', value: 'Office: ' + office }]);                     var r2 = Addrow(2, [{ key: 'A', value: 'Department: ' + department }]);                                               var r3 = Addrow(3, [{ key: 'A', value: 'Search Keyword: ' + search }]);                     var r4 = Addrow(4, [{ key: 'A', value: '' }]);                                  var sheetData = sheet.getElementsByTagName('sheetData')[0];                      sheetData.insertBefore(r4,sheetData.childNodes[0]);                     sheetData.insertBefore(r3,sheetData.childNodes[0]);                     sheetData.insertBefore(r2,sheetData.childNodes[0]);                     sheetData.insertBefore(r1,sheetData.childNodes[0]); 

DEMO: https://output.jsbin.com/kevosub/

Read More

Wednesday, April 27, 2016

Cannot read property 'aDataSort' of undefined in angular datatables

Leave a Comment

I am trying to implement angular-datatables in my project but it returns "TypeError: Cannot read property 'aDataSort' of undefined

I am using

Angular js version 1.4.9.

Jquery version 2.1.1

DataTable version 1.10.10

Refrence site

angular-datatables

My Html Code

<div class="col-md-12" ng-controller="WithAjaxCtrl as showCase"> <table datatable="" dt-options="showCase.dtOptions" dt-columns="showCase.dtColumns" class="row-border hover"></table></div> 

My Angular js Controller code

angular.module( 'admin.package', [ 'ui.router', 'ui.bootstrap', 'datatables', 'datatables.bootstrap', 'ngResource', 'plusOne' ]).controller('WithAjaxCtrl', WithAjaxCtrl);  function WithAjaxCtrl(DTOptionsBuilder, DTColumnBuilder,$http,UserService,localStorageService) {       UserService.obj.get('packages/index',localStorageService.get('userkey').token).then(function (results) {          if(results.status==200){         var vm = this;         vm.dtOptions = DTOptionsBuilder.fromSource(results.data.packages)             .withPaginationType('full_numbers');         vm.dtColumns = [            DTColumnBuilder.newColumn('id').withTitle('id'),             DTColumnBuilder.newColumn('package_name').withTitle('Packag Name'),             DTColumnBuilder.newColumn('amount').withTitle('Amount'),             DTColumnBuilder.newColumn('package_duration').withTitle('Amount'),             DTColumnBuilder.newColumn('currency').withTitle('validity')          ];         console.log(vm.dtColumns);         console.log( vm.dtOptions);       }else{              alert('You are not a authorized user');           }         }, function(reason) {             console.log(reason);         });     } 

Thanks in advance

1 Answers

Answers 1

You are passing showCase.dtOptions and showCase.dtColumns to the datatables directives when the page loads, but they are not declared until after your service call is completed. One workaround for this would be to use ng-if to construct the html after the service call:

<table ng-if="showCase.authorized" datatable="" ... 

Then in your controller, initialize the variable before calling the service, and updating it after the call is complete:

app.controller('WithAjaxCtrl', function WithAjaxCtrl(DTOptionsBuilder, DTColumnBuilder, UserService) {   var vm = this;   vm.authorized = false;   UserService.get()... 

Here is a demo. You can reproduce the error by removing the ng-if. http://plnkr.co/edit/XZYOEvgy1HoMYGmGdAYj?p=preview

Read More

Friday, April 15, 2016

Sorting arrow is shown for first column even when sorting is disabled

Leave a Comment

I need add "Select all" checkbox in table with using DataTable pligin. I don't found standard method for this and I use addition by manually for this. All Ok, but if I try use localization ('language' property) my "All select" checkbox disappears. I try fix is by add my code in DataTable library, but it is bad way.

  <table id="devices" class="table table-striped table-bordered" cellspacing="0" width="100%">     <thead>       <tr>         <th style="padding:8px; text-align:center;">                         <input type='checkbox' class='minimal check-all' id='check-all-device' name='check-all-device'></input>          </th>         <th>{% trans "STATUS" %}</th>         <th>{% trans "DEVICE NAME" %}</th>         <th>{% trans "ACTIONS" %}</th>         <th></th>       </tr>     </thead>      <tfoot>         <tr>             <th></th>             <th>{% trans "STATUS" %}</th>             <th>{% trans "DEVICE NAME" %}</th>             <th>{% trans "ACTIONS" %}</th>             <th></th>         </tr>     </tfoot>      <tbody id="devices-table-rows">       {% for device in object_list %}         {% include "device_add_row.html" %}       {% endfor %}     </tbody>   </table> 

Add handlers of selection on javascript:

devicesTable = $('#devices').DataTable({     // disable sorting first column     'aoColumnDefs': [{         'bSortable': false,         'aTargets': [0] /* 1st one, start by the right */     }],     stateSave: false });  // Action's select insert in to search row $('#devices_filter').append($('#devices-actions'));      // Settings Check ALL var firstTh = $($($('#devices > thead').find('tr')[0]).find('th')[0]); firstTh.removeClass("sorting_asc");   //iCheck for checkbox and radio inputs $('input[type="checkbox"].minimal, input[type="radio"].minimal').iCheck({     checkboxClass: 'icheckbox_minimal-blue',     radioClass: 'iradio_minimal-blue' });  // Check handlers All var checkAll = $('input.check-all'); var checkboxes = $('input.check-single');  checkAll.on('ifChecked ifUnchecked', function(event) {     if (event.type == 'ifChecked') {         checkboxes.iCheck('check');     } else {         checkboxes.iCheck('uncheck');     } });  checkboxes.on('ifChanged', function(event){     if(checkboxes.filter(':checked').length == checkboxes.length) {         checkAll.prop('checked', 'checked');     } else {         checkAll.removeProp('checked');         checkAll.prop('checked', false);     }     checkAll.iCheck('update'); }); 

Result - all right!:

enter image description here

Add using language for table localization:

var languageUrl = "https://cdn.datatables.net/plug-ins/1.10.11/i18n/Russian.json"; }  devicesTable = $('#devices').DataTable({     // disable sorting first column     'aoColumnDefs': [{         'bSortable': false,         'aTargets': [0] /* 1st one, start by the right */     }],     stateSave: false,     language: {         "url": languageUrl     } }); 

My settings is reset:

enter image description here

1 Answers

Answers 1

Sorting

Option orderable only controls end-user ability to sort the column. This doesn't prevent the column from being sorted programmatically.

Default value for order option which controls how the table is sorted is [[0, 'asc']]. Use this option to set initial sorting order other than first column.

For example:

devicesTable = $('#devices').DataTable({     // disable sorting first column     'columnDefs': [{         'orderable': false,         'targets': 0 /* 1st one, start by the right */     }],     order: [[2, 'asc']],      stateSave: false,     language: {         "url": "https://cdn.datatables.net/plug-ins/1.10.11/i18n/Russian.json"     } }); 

Checkboxes

You need to initialize checkboxes in drawCallback handler and use delegated event handlers. Otherwise only checkboxes on the first page would work.

Please note that I just copied parts your code related to iCheck plug-in and cannot guarantee that it will work. The important part of the example below is use of drawCallback and delegated event handlers.

devicesTable = $('#devices').DataTable({     // disable sorting first column     'columnDefs': [{         'orderable': false,         'targets': 0 /* 1st one, start by the right */     }],     order: [[2, 'asc']],      stateSave: false,     language: {         "url": "https://cdn.datatables.net/plug-ins/1.10.11/i18n/Russian.json"     },     drawCallback: function(settings){        var api = this.api();        //iCheck for checkbox and radio inputs       $('input[type="checkbox"].minimal, input[type="radio"].minimal', api.table().node()).iCheck({          checkboxClass: 'icheckbox_minimal-blue',          radioClass: 'iradio_minimal-blue'       });     } });  var table_node = devicesTable.table().node();  $('thead', table_node).on('ifChecked ifUnchecked', 'input.check-all', function(event) {     var checkboxes = $('tbody input.check-single', table_node);      if (event.type == 'ifChecked') {         checkboxes.iCheck('check');     } else {         checkboxes.iCheck('uncheck');     } });  $('tbody', table_node).on('ifChanged', 'input.check-single', function(event) {     var checkAll = $('thead input.check-all', table_node);      var checkboxes = $('tbody input.check-single', table_node);      if(checkboxes.filter(':checked').length == checkboxes.length) {         checkAll.prop('checked', 'checked');     } else {         checkAll.removeProp('checked');         checkAll.prop('checked', false);     }     checkAll.iCheck('update'); }); 
Read More

Saturday, April 2, 2016

JQuery Datatables makeEditable() issues with large dataset

Leave a Comment

I'm following this tutorial to implement cell editing in JQuery datatables with MVC4.

Links to the plugins used are:

  1. jQuery DataTables plug-in v1.7.5., including the optional DataTables CSS style-sheets used for applying the default styles on the page
  2. jQuery Jeditable plug-in v1.6.2., required for inline cell editing
  3. jQuery validation plug-in v1.7., for implementation of client-side validation
  4. jQuery DataTables Editable plug-in that integrates all these mentioned plug-ins into a fully functional editable datatable.

To achieve the effect of creating the editable datatable you simply have to include the following as part of your script

<script>     $(document).ready(function () {        $('#myDataTable').dataTable().makeEditable();     }); </script> 

The Problem

For each column present in the grid an event is created in the DOM to allow editing.

Where the dataset is very large this has proven to cause significant issues even crashing my browser.


The overall question

Is it possible to only call the edit logic when the user selects the appropriate column rather than trying to build up a large amount of events in the DOM?

5 Answers

Answers 1

I don't use makeEditable() with very large datasets, but you might get a performance benefit from an uplift of some of your versions. I am using:

  • jquery 1.6.4
  • datatables 1.8.2
  • jeditable 1.7.3
  • jQuery Validation Plugin 1.11.1
  • datatables.editable 2.3.1

Answers 2

One alternative is add the event when the user clicking in the td.

$(document).ready(function() {      oTable = $('#example').dataTable();      $("#example td").on("click",function(){         $(this).editable();     })  }); 

Example: https://jsfiddle.net/cmedina/7kfmyw6x/32/

Now, if you do not want to edit all the columns you can assign the event editable only for some columns per class

var oTable = $('#table_id').dataTable(     {          "bSort": false,          "sPaginationType": "full_numbers",     });  $('td.editable_class', oTable.fnGetNodes()).editable('editable.php', { "callback": function( sValue, y ) {     var aPos = oTable.fnGetPosition( this );     oTable.fnUpdate( sValue, aPos[0], aPos[1] ); }, "submitdata": function ( value, settings ) {     return {         "row_id": $(this).data('id'),         "column": $(this).data('column'),     }; }, "height": "17px", "width": "100%", }); 

Answers 3

You can make the td editable on click:

$("#example td").on("click",function(){     $(this).editable(); }) 

Answers 4

In addition to @CMedina 's answer, please read:

.on() - Direct and delegated events

In addition to their ability to handle events on descendant elements not yet created, another advantage of delegated events is their potential for much lower overhead when many elements must be monitored.

On a data table with 1,000 td elements in #example, this example attaches a handler to 1,000 elements:

$("#example td").on("click",function(){     $(this).editable(); }) 

An event-delegation approach attaches an event handler to only one element, the #example, and the event only needs to bubble up one level (from the clicked td to #example):

$("#example").on("click", "td", function(){     $(this).editable(); }) 

Answers 5

I'm not familiar with this library, however i suggest to check if the views and stored procedure is supported, after that you can customize the number of columns required.

Read More