0

I have the following AngularJS template file:

<div ng-controller="PredictionCtrl as predictionCtrl">
  <table width="40%" border="1">
    <tbody>
      <tr>
        <td bgcolor="orange">A</td>
        <td bgcolor="yellow">B</td>
      </tr>
    </tbody>
    <tfoot>
      <tr>
        <td bgcolor="pink">C</td>
        <td bgcolor="cyan">D</td>
      </tr>
    </tfoot>
  </table>
  <br>

  <table width="40%" border="1">
    <tbody>
      <rpt-my-directive-a p="1" q="2"></rpt-my-directive-a>
    </tbody>
    <tfoot>
      <rpt-my-directive-b r="3" s="4"></rpt-my-directive-a>
    </tfoot>
  </table>
</div>

In the template for my directive myDirectiveA, I have the following:

<tr>
  <td bgcolor="orange">E</td>
  <td bgcolor="yellow">F</td>
</tr>

In the template for my directive myDirectiveB, I have the following:

<tr>
  <td bgcolor="pink">G</td>
  <td bgcolor="cyan">H</td>
</tr>

The output looks like this:

enter image description here

I was expecting two identical-looking tables. Instead I got one with the proper colors and one without. Why did the table that was constructed using AngularJS directives come out looking different than the plain-HTML one?? How do I fix this? I want the second table to look just like the first.

EDIT #1:

When I took Sergey's advice below, the declaration for myDirectiveA now looks like this:

myApp.directive('myDirectiveA',function(){
    return {
      restrict:'A',
      replace: true,
      scope: {
        p: '=',
        q: '='
      },
      controller: 'MyDirectiveACtrl',
      controllerAs: 'MyDirectiveACtrl',
      bindToController: true,
      template: '<div ng-include="MyDirectiveACtrl.myDirectiveAHTML"></div>'
    };
  }
);

and the output now looks like this:

enter image description here

Saqib Ali
  • 11,931
  • 41
  • 133
  • 272

2 Answers2

1

With tables you need nest your elements correctly. So you cant nest custom tag inside tbody tag, the same with TR ... So please use attributes restriction for directives for that case.

Makarov Sergey
  • 932
  • 7
  • 21
1

I'm new to Stackoverflow, so I couldn't comment On Sergey's answer. But I'm pretty sure he meant this: https://jsfiddle.net/a41o54ec

On this line:

template: '<div ng-include="MyDirectiveACtrl.myDirectiveAHTML"></div>'

That div needs to be a tr. And then I hope MyDirectiveACtrl.myDirectiveAHTML is something like <td>whatever</td>. I would recommend simply changing the template to this:

template: '<tr><td ng-include="MyDirectiveACtrl.myDirectiveAHTML"><td></tr>'

With tr>td in the template, the contents of MyDirectiveACtrl.myDirectiveAHTML can be almost anything.

EDIT #1

If the template must contain several rows i would recommend creating an external .html and use templateUrl instead. Like this...

New file: myDirectiveA.template.html:

<tr>
  <td bgcolor="orange">E</td>
  <td bgcolor="yellow">F</td>
</tr>
<tr>
  <td bgcolor="orange">E</td>
  <td bgcolor="yellow">F</td>
</tr>

On the directive definition remove template:... and do:

templateUrl: "path/to/myDirectiveA.template.html"

EDIT #2

FAIL! on my part! It is true that when using templateUrl, myDirectiveA.template.html MUST contain a single parent element. That means that this:

<tr>
  <td bgcolor="orange">E</td>
  <td bgcolor="yellow">F</td>
</tr>
<tr>
  <td bgcolor="orange">E</td>
  <td bgcolor="yellow">F</td>
</tr>

can't be done on the template... Since we are playing with tables, there's only a few elements that could be a parent for several <tr>. Being <table>, <tbody>, and a few others.

Since tables limit the element types you can use, you have to clearly define what you are doing with these directives. You reached a point where you have to decide if you are using a directive per row or a directive per table.

If you keep the directive as we defined it before, that means your template can only contain one row. We defined a directive-per-row model.

If you do want multiple rows on your template you must then apply the directive to table or tbody. I would do it to table and let one directive control the whole table.

<table width="40%" border="1"
  rpt-my-directive-a
  p="1"
  q="2"
  >
</table>

Also, remove this line from your directive definition. Otherwise, the <table> element will get replaced by the contents of the template.

replace:true // REMOVE ME!

By doing this... myDirectiveA.template.html can now have tbody as a parent element and the warning will go away.

// myDirectiveA.template.html
<tbody>
  <tr>
    <td bgcolor="orange">E</td>
    <td bgcolor="yellow">F</td>
  </tr>
  <tr>
    <td bgcolor="orange">E</td>
    <td bgcolor="yellow">F</td>
  </tr>
</tbody>
Jairo Dev
  • 51
  • 4
  • Will this work if the directive's HTML contains multiple rows of pairs? The reason I'm asking is because I'm using this to build a table. Some of the rows of the table are in `myDirectiveA` and some are in `myDirectiveB` – Saqib Ali Sep 24 '16 at 12:12
  • 1
    Yes... I created **Edit #1** to explain the use of tempalteUrl instead. I am guessing that you probably didn´t know **templateUrl** and maybe that's why you where trying to use ng-include? Anyways, let me know if the EDIT helps – Jairo Dev Sep 24 '16 at 19:39
  • Thanks Jairo!! `templateUrl` was very helpful! So was your fiddle. The only problem I'm having is that it when I change myDirectiveA.template such that it now conatinas two `` rows instead of one, I get the following error: `angular.js:13920 Error: [$compile:tplrt] Template for directive 'rptMyDirectiveA' must have exactly one root element. path/to/myDirectiveA.template.html`. What's the proper way to get around this issue?? – Saqib Ali Sep 25 '16 at 03:50
  • Thanks Jairo!! templateUrl was very helpful! So was your fiddle. The only problem I'm having is that it when I change myDirectiveA.template such that it now conatinas two rows instead of one, I get the following error: angular.js:13920 Error: [$compile:tplrt] Template for directive 'rptMyDirectiveA' must have exactly one root element. path/to/myDirectiveA.template.html. What's the proper way to get around this issue?? I posted this as its own question right here: http://stackoverflow.com/questions/39683523/angularjs-error-template-for-directive-xxxxxx-must-have-exactly-one-root-elem – Saqib Ali Sep 25 '16 at 04:54
  • TRUE! The template has to contain a single parent element. In our current case that means a single **tr**. Tables are tricky man. Please check out **EDIT #2** – Jairo Dev Sep 25 '16 at 19:18