Pavel Shkleinik
Pavel Shkleinik

Reputation: 6347

AngularJS complex table header

I'm developing Timesheet application. I have ready layout (html/css). Currently I'm working on layout behavior. My current goal is extracting timesheet table header in directive. Angular template html should look similar to this:

<colgroup class="col_day">
    <col ng-repeat="day in header.days" ng-class="someConditions">
</colgroup>
<thead>
    <tr>
        <th ng-repeat="day in header.days" ng-class="someConditions">
            {{someLayout}}
        </th>
    </tr>
</thead>

I want to use this template via directive like this:

<table>
    <timesheet-header></timesheet-header>
    <tbody></tbody>
    <tfoot></tfoot>
</table>

Problems:

I have only bad solutions:

Note: I'm using AngularJS v1.4.3. Debugging in latest Google Chrome.

Upvotes: 2

Views: 1037

Answers (2)

Bharat
Bharat

Reputation: 943

"Create two different directives for colgroup and thead (this solves multiple roots, but html will still appear outside table tag)" - You can find more details for this behavior in https://github.com/angular/angular.js/issues/1459. And specifically in https://github.com/angular/angular.js/issues/1459#issuecomment-67235182

You can solve this issue using transclude and custom directive for table as attribute

http://plnkr.co/edit/8JptrwUcA0pPl9xB9yZQ?p=preview

<table my-table>
  <tbody>
    <tr>
      <td>4</td>
      <td>5</td>
    </tr>
  </tbody>
</table>

.directive('myTable', [function() {
  return {
    restrict: 'A',
    transclude: true,
     template: '<table>' +
              '<colgroup class="col_day"><col ng-repeat="n in [1, 2] track by $index">{{n}}</col></colgroup>' +
               '<thead>' +
                  '<tr>' +
                    '<th ng-repeat="n in [1, 2] track by $index"> {{n}}</th>' +
                  '</tr>' +
                '</thead>' +
                '<div ng-transclude></div>' +
            '</table>'
      };
  }]) 

Upvotes: 0

SamHuckaby
SamHuckaby

Reputation: 1162

Okay, so the attribute directive was in fact the right way to go, it just took a little bit to realize how the changes to transclude work in newer versions of Angular.

So, with the newer versions of Angular, ng-transclude actually removes everything inside of the directive. It turns out though that when you use the transclude option on your directive, Angular actually exposes a function to you in the link function that allows you to manually handle the transcluded content. Once you have this, you can tell it to simply append the content instead of replace it like it does by default.

Some good reading on the subject can be found here: http://ng.malsup.com/#!/transclude-function

template:

<table>
  <colgroup class="col_day">
      <col ng-repeat="day in header.days" ng-class="someConditions">
  </colgroup>
  <thead>
      <tr>
          <th ng-repeat="day in header.days" ng-class="someConditions">
              {{someLayout}}
          </th>
      </tr>
  </thead>
</table>

directive:

app.directive('timesheetHeader', function() {
  return {
    restrict: 'A',
    replace: true,
    transclude: true,
    templateUrl: 'timesheet-header.template.html',
    link: function(scope, el, attrs, ctrl, transcludeFn) {
      var transcludedContent = transcludeFn();
      el.append( transcludedContent );
    }
  };
});

Actual HTML Code:

<table timesheet-header>
    <tbody>
        <tr>
            <td>Hello</td>
            <td>world!</td>
        </tr>
    </tbody>
    <tfoot></tfoot>
</table>

Upvotes: 1

Related Questions