8
votes

I have a requirement to show a 5 column table data with 3 column header similar to the below screenshot (Please igonre the 1st column in table body with yellow star).

enter image description here

Help me with couple of problems given below.

  1. When I provide explicit header values inside thead to do a colspan of 3 for last 3 runs, I do not get filters.
  2. Is it correct/best way to do a select filter using filterStatusFor0($column), filterStatusFor1($column) & filterStatusFor2($column) in my code?

ngtable

<div class="col-md-8">
    <table ng-table="taskDetailTableParams" show-filter="true" class="table upgradeTaskDetailTable text-left table-bordered">
        <thead>
            <th>Task Name</th>
            <th>Type of Task</th>
            <th colspan="3">Last 3 runs</th>
        </thead>
        <tbody>            
            <tr ng-repeat="item in $data" height="10px" class="animate" ng-animate="{enter: 'animate-enter', leave: 'animate-leave'}">
                <td data-title="'Task Name'" class="text-left col-sm-4 col-md-4 col-lg-4" header-class="text-left" filter="{ 'name': 'text' }" sortable="'name'">{{ item.name }}</td>
                <td data-title="'Type of Task'" class="text-left col-sm-2 col-md-2 col-lg-2" header-class="text-left" filter="{ 'type': 'text' }" sortable="'type'">{{item.type}}</td>
                <td data-title="'latest Run'" class="text-left col-sm-2 col-md-2 col-lg-2" header-class="text-left" filter="{ 'selectIdFor0': 'select' }" sortable="'selectIdFor0'" filter-data="filterStatusFor0($column)"><img ng-src="{{ item.statusImageFor0 }}" title="{{ item.statusFor0 }}" data-toggle="tooltip" data-placement="bottom" /></td>
                <td data-title="'2nd Latest Run'" class="text-left col-sm-2 col-md-2 col-lg-2" header-class="text-left" filter="{ 'selectIdFor1': 'select' }" sortable="'selectIdFor1'" filter-data="filterStatusFor1($column)"><img ng-src="{{ item.statusImageFor1 }}" title="{{ item.statusFor1 }}" data-toggle="tooltip" data-placement="bottom" /></td>
                <td data-title="'3rd Latest Run'" class="text-left col-sm-2 col-md-2 col-lg-2" header-class="text-left" filter="{ 'selectIdFor2': 'select' }" sortable="'selectIdFor2'" filter-data="filterStatusFor2($column)"><img ng-src="{{ item.statusImageFor2 }}" title="{{ item.statusFor2 }}" data-toggle="tooltip" data-placement="bottom" /></td>
            </tr>
        </tbody>
    </table>
</div>

Select filter code

$scope.filterStatusFor0 = function(column) {
    var def = $q.defer(),
        arr = [],
        filterStatus = [];
    angular.forEach($scope.taskDetailData, function(item) {
        if (jQuery.inArray(item.selectIdFor0, arr) === -1) {
            arr.push(item.selectIdFor0);
            filterStatus.push({
                'id': item.selectIdFor0,
                'title': item.statusFor0
            });
        }
    });
    filterStatus.sort(function(a, b) {
        if (a.id < b.id)
            return -1;
        if (a.id > b.id)
            return 1;
        return 0;
    });
    def.resolve(filterStatus);
    return def;
};

Please check this plunker link

1

1 Answers

1
votes

You could add a custom header with template-header="my_header.html" as direcitve attribute and then the easiest way to get your colgroup would be to add a row above the normal header template.

So it's easier to have all the filters in place and for the other empty cells in that row you could do css styling to remove the borders to have a better looking table. (Not added in the updated plunkr).

For the second part of your question with the filter method. You're repeating the same code three times (that's not following DRY principle).

You could improve that by adding an id to your function so you'll only have one filter method that's just called with different ids.

Below is the updated code with the added custom header template. You can also find the code in this plunkr.

var app = angular.module('main', ['ngTable'])
  .controller('DemoCtrl', function($scope, $q, $filter, ngTableParams, $log) {

    $scope.taskDetailData = [{
      "index": 0,
      "id": "000ABC0G000000000WQQ",
      "name": "Jaantestsameepidentity",
      "type": "Hadoop",
      "statusFor0": "Failed",
      "selectIdFor0": "Failed",
      "statusImageFor0": "http://i.imgur.com/knyz0Ye.png",
      "statusFor1": "Failed",
      "selectIdFor1": "Failed",
      "statusImageFor1": "http://i.imgur.com/knyz0Ye.png",
      "statusFor2": "Failed",
      "selectIdFor2": "Failed",
      "statusImageFor2": "http://i.imgur.com/knyz0Ye.png"
    }, {
      "index": 1,
      "id": "000ABC0I000000000WQC",
      "name": "Salesorder_netsuite",
      "type": "Salesforce",
      "statusFor2": "No runs available",
      "statusFor1": "No runs available",
      "selectIdFor2": "stopped",
      "selectIdFor1": "stopped",
      "statusImageFor2": "http://i.imgur.com/L5c69tb.png",
      "statusImageFor1": "http://i.imgur.com/L5c69tb.png",
      "statusFor0": "Success",
      "selectIdFor0": "Success",
      "statusImageFor0": "http://i.imgur.com/ZkAwklS.png"
    }, {
      "index": 2,
      "id": "000ABC0I000000000WQW",
      "name": "today_record",
      "type": "Oracle",
      "statusFor2": "No runs available",
      "statusFor1": "No runs available",
      "selectIdFor2": "stopped",
      "selectIdFor1": "stopped",
      "statusImageFor2": "http://i.imgur.com/L5c69tb.png",
      "statusImageFor1": "http://i.imgur.com/L5c69tb.png",
      "statusFor0": "Success",
      "selectIdFor0": "Success",
      "statusImageFor0": "http://i.imgur.com/ZkAwklS.png"
    }];
    $scope.taskDetailTableParams = new ngTableParams({
      page: 1, // show first page
      count: 10, // count per page
      sorting: {
        index: 'asc' // initial sorting
      }
    }, {
      total: $scope.taskDetailData.length, // length of data
      getData: function($defer, params) {
        var filterData = params.filter() ? $filter('filter')($scope.taskDetailData, params.filter()) : $scope.taskDetailData;
        var orderedData = params.sorting() ? $filter('orderBy')(filterData, params.orderBy()) : filterData;
        var table_data = orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count());
        params.total(orderedData.length);
        $defer.resolve(table_data);
      }
    });

    /**
     * Filter for ngtable (Below 3 functions)
     * @return {[type]}        [description]
     */
    $scope.filterStatus = function(column, id) { // for0 --> moved to id
      //console.log(column);
      var def = $q.defer(),
        arr = [],
        filterStatus = [];
      angular.forEach($scope.taskDetailData, function(item) {
        //console.log(item.selectIdFor0, item['selectIdFor' + id])
        if (jQuery.inArray(item['selectIdFor' + id], arr) === -1) {
          arr.push(item['selectIdFor' + id]);
          filterStatus.push({
            'id': item['selectIdFor' + id],
            'title': item['statusFor' + id]
          });
        }
      });
      filterStatus.sort(function(a, b) {
        if (a.id < b.id)
          return -1;
        if (a.id > b.id)
          return 1;
        return 0;
      });
      def.resolve(filterStatus);
      return def;
    };
  });
<link href="https://cdnjs.cloudflare.com/ajax/libs/ng-table/0.3.3/ng-table.min.css" rel="stylesheet" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.2/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ng-table/0.3.3/ng-table.min.js"></script>
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>

<div ng-app="main" ng-controller="DemoCtrl">
  
  <script type="text/ng-template" id="aw_ngtable_header.html">
      <tr>
      <!-- add new row above normal header for last 3 runs colgroup -->
        <th ng-repeat="n in [].constructor($columns.length-2) track by $index" colspan="{{lastThree = ($index == $columns.length -3)? 3:''}}">
          <span ng-if="lastThree">Last 3 runs</span>
        </th>
        </tr>
       <tr>
          <th ng-repeat="column in $columns"
            ng-class="{
                        'sortable': parse(column.sortable),
                        'sort-asc': params.sorting()[parse(column.sortable)]=='asc',
                        'sort-desc': params.sorting()[parse(column.sortable)]=='desc'
                      }"
            ng-click="sortBy(column, $event)"
            ng-show="column.show(this)"
            ng-init="template = column.headerTemplateURL(this)"
            class="header {{column.class}}">
            <div ng-if="!template" ng-show="!template" ng-bind="parse(column.title)"></div>
            <div ng-if="template" ng-show="template"><div ng-include="template"></div></div>
        </th>
    </tr>
    <tr ng-show="show_filter" class="ng-table-filters">
        <th ng-repeat="column in $columns" ng-show="column.show(this)" class="filter">
            <div ng-repeat="(name, filter) in column.filter">
                <div ng-if="column.filterTemplateURL" ng-show="column.filterTemplateURL">
                  <div ng-include="column.filterTemplateURL"></div>
                </div>
                <div ng-if="!column.filterTemplateURL" ng-show="!column.filterTemplateURL">
                    <div ng-include="'ng-table/filters/' + filter + '.html'"></div>
                </div>
            </div>
        </th>
    </tr>
  </script>
  
  
  <table ng-table="taskDetailTableParams" template-header="aw_ngtable_header.html" show-filter="true" class="table upgradeTaskDetailTable text-left table-bordered">
    <!--<thead>
            <th>Task Name</th>
            <th>Type of Task</th>
            <th colspan="3">Last 3 runs</th>
        </thead>-->
    <tr ng-repeat="item in $data" height="10px" class="animate" ng-animate="{enter: 'animate-enter', leave: 'animate-leave'}">
      <td data-title="'Task Name'" class="text-left col-sm-4 col-md-4 col-lg-4" header-class="text-left" filter="{ 'name': 'text' }" sortable="'name'">{{ item.name }}</td>
      <td data-title="'Type of Task'" class="text-left col-sm-2 col-md-2 col-lg-2" header-class="text-left" filter="{ 'type': 'text' }" sortable="'type'">{{item.type}}</td>
      <td data-title="'latest Run'" class="text-left col-sm-2 col-md-2 col-lg-2" header-class="text-left" filter="{ 'selectIdFor0': 'select' }" sortable="'selectIdFor0'" filter-data="filterStatus($column, 0)">
        <img ng-src="{{ item.statusImageFor0 }}" title="{{ item.statusFor0 }}" data-toggle="tooltip" data-placement="bottom" />
      </td>
      <td data-title="'2nd Latest Run'" class="text-left col-sm-2 col-md-2 col-lg-2" header-class="text-left" filter="{ 'selectIdFor1': 'select' }" sortable="'selectIdFor1'" filter-data="filterStatus($column, 1)">
        <img ng-src="{{ item.statusImageFor1 }}" title="{{ item.statusFor1 }}" data-toggle="tooltip" data-placement="bottom" />
      </td>
      <td data-title="'3rd Latest Run'" class="text-left col-sm-2 col-md-2 col-lg-2" header-class="text-left" filter="{ 'selectIdFor2': 'select' }" sortable="'selectIdFor2'" filter-data="filterStatus($column, 2)">
        <img ng-src="{{ item.statusImageFor2 }}" title="{{ item.statusFor2 }}" data-toggle="tooltip" data-placement="bottom" />
      </td>
    </tr>
  </table>
</div>