2

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:

  • Angular doesn't allow to use multiple roots in template in directives with replace: true
  • Template content appears outside of tag (only if template contains single tag it is rendered inside table

I have only bad solutions:

  • Create two different directives for colgroup and thead (this solves multiple roots, but html will still appear outside table tag)
  • keep template binding results invisible and prepend copy of generated html to table (by jquery)
  • use the directive as attribute for table tag... I tried but this removes all other table content (I tried transclude)...

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

4
  • Are you sure that when you create two different directives, the HTML contents of these directives appear outside the table tag? Commented Aug 19, 2015 at 13:41
  • Yep, I tried multiple times. I even tried to simplify my template to pure single-tag html. Only <tr> tag appears inside <table>. All other tags (single <colgroup> or single <thead>) appear outside <table> (before). Commented Aug 19, 2015 at 13:48
  • I feel like an attribute directive with transclude is the right answer here. Can you give me a little more information about what was happening when you tried that? Commented Aug 19, 2015 at 15:09
  • Before there was a big angular controller and extensive html. I started pulling parts of the code to separate directive and faced with the described problem. When I try to use Element-Directive inside <table> the template html is pushed out of the <table>. Feel free to request any details you need. Commented Aug 19, 2015 at 15:21

2 Answers 2

1

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>
Sign up to request clarification or add additional context in comments.

2 Comments

thank you for your great answer! It works fine for me now. I'm going to add some angular directives inside trunscluded content, hope it will work =)
Awesome! I'm glad I could help.
0

"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>'
      };
  }]) 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.