6

I'm using Angular-Datatables. I need to be able to dynamically create the table based on the data that is being returned. In other words, I do not want to specify the column headers.

Example:

json data:

[
 {
  "id": "2",
  "city": "Baltimore",
  "state": "MD",
 },
 {
  "id": "5",
  "city": "Boston",
  "state": "MA",
 },
 {
  "id": "8",
  "city": "Malvern",
  "state": "PA",
 },
]

Column Headers:

id, city, state

Can someone please help with this?

Sharath
  • 691
  • 8
  • 23
Met-u
  • 555
  • 7
  • 18

3 Answers3

5

That is actually a good question! With traditional jQuery dataTables it is not a problem, but we have a different kind of declarative setup with angular dataTables, making it more difficult to separate the various tasks. We can delay the population of data with fromFnPromise, but not prevent the dataTable from being instantiated before we want it. I think I have found a solid solution :

First, to avoid instant initialization remove the datatable directive from the markup and give the <table> an id instead, i.e :

<table id="example" dt-options="dtOptions" dt-columns="dtColumns" />

Then load the data resource, build dtColumns and dtOptions and finally inject the datatable attribute and $compile the <table> using the id :

$http({
  url: 'data.json'
}).success(function(data) {
  var sample = data[0], dtColumns = []

  //create columns based on first row in dataset
  for (var key in sample) dtColumns.push(
    DTColumnBuilder.newColumn(key).withTitle(key)
  )
  $scope.dtColumns = dtColumns

  //create options
  $scope.dtOptions = DTOptionsBuilder.newOptions()
    .withOption('data', data)
    .withOption('dataSrc', '')

  //initialize the dataTable
  angular.element('#example').attr('datatable', '')
  $compile(angular.element('#example'))($scope)
})

This should work with any "array of objects" resource
Demo -> http://plnkr.co/edit/TzBaaZ2Msd9WchfLDLkN?p=preview


NB: Have cleaned up the example JSON, I guess it was a sample and not meant to be working with trailing commas.

davidkonrad
  • 83,997
  • 17
  • 205
  • 265
  • Thanks! This definitely makes sense. I'll implement the solution on my side and update this as an accepted answer thereafter. Thanks again! – Met-u Aug 10 '16 at 08:53
  • @Sana, Thank you for taking notice. Have fixed the plunkr. It did not work because the author of Angular DataTables for some reason decided to build AD for angular 2/4/5 on top of the existing branch, so any references without specific version does no longer work :( – davidkonrad Jan 18 '18 at 13:29
  • Any idea how to do it with nested JSON objects – Sana Ahmed Jan 18 '18 at 14:01
5

Being faced with the same problem, I actually found an easier to implement and much simpler (and safer because of not using $compile) solution.

The only change needed to be made to the html is the addition of an ng-if:

<table ng-if="columnsReady" datatable="" dt-options="dtOptions" dt-columns="dtColumns"/>

What happens is that angular will delay the creation of this node till columnsReady has any value. So now in your code you can get the data you need, and when you have it, you can just set columnsReady to true and angular will do the rest.

$http({
  url: 'data.json'
}).success(function(data) {
  var sample = data[0], dtColumns = []

  //create columns based on first row in dataset
  for (var key in sample) dtColumns.push(
    DTColumnBuilder.newColumn(key).withTitle(key)
  )
  $scope.dtColumns = dtColumns

  //create options
  $scope.dtOptions = DTOptionsBuilder.newOptions()
    .withOption('data', data)
    .withOption('dataSrc', '')

  //initialize the dataTable
  $scope.columnsReady = true;
});
Rabbi Shuki Gur
  • 1,656
  • 19
  • 36
  • 1
    great solution. – Luke Becker Jan 26 '18 at 22:37
  • 1
    This helped me immensely trying to implement loading 'fromFnPromise". Putting a Datatables into a uib-tab the promise was always being fetched on page load. Hiding the table in non-visible tabs with "ng-if" and then toggling the boolean works a treat. Many thanks. – greg Jan 02 '21 at 18:48
-2

Below code which will give you table dynamically based on data

HTML

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

JS

angular.module('showcase.withAjax',['datatables']).controller('WithAjaxCtrl', WithAjaxCtrl);

function WithAjaxCtrl(DTOptionsBuilder, DTColumnBuilder) {
var vm = this;
vm.dtOptions = DTOptionsBuilder.fromSource('data.json')
    .withPaginationType('full_numbers');
vm.dtColumns = [
    DTColumnBuilder.newColumn('id').withTitle('ID'),
    DTColumnBuilder.newColumn('city').withTitle('City'),
    DTColumnBuilder.newColumn('state').withTitle('State')
];

}

data.json

[{
"id": 860,
"city": "Superman",
"state": "Yoda"
}, {
"id": 870,
"city": "Foo",
"state": "Whateveryournameis"
}, {
"id": 590,
"city": "Toto",
"state": "Titi"
}, {
"id": 803,
"city": "Luke",
"state": "Kyle"
 },
 ...
 ]
Jaldhi Oza
  • 92
  • 5
  • This is exactly what I'm trying to avoid. I do not want to have to specify the column headers with vm.dtColumns – Met-u Aug 05 '16 at 14:23