Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS ng-repeat with custom element inside a table is rendering strangely

I'm trying to re-use a portion of my HTML view in multiple places. The portion I want to re-use is table cells in an HTML table. The problem is that my custom directive inside a ng-repeat is doing funny things. I have reproduced the problem on jsFiddle. There are two HTML tables in the jsFiddle. The first is ng-repeat with the table cells written in the view and the second is the table cells coming from a directive, my-element. Chrome dev tools report that the rendered HTML looks like this. Note that the custom element appears only once and is outside the table.

Rendered HTML

<div ng-controller="MyCtrl" class="ng-scope">     table1     <table class="table table-hover">       <tbody><!-- ngRepeat: p in people -->           <tr ng-repeat="p in people" class="ng-scope">             <td class="ng-binding">Name: Mike</td>             <td class="ng-binding">Age: 20</td>           </tr>           <tr ng-repeat="p in people" class="ng-scope">             <td class="ng-binding">Name: Peter S</td>             <td class="ng-binding">Age: 22</td>           </tr>       </tbody>     </table>     <br>table2     <my-element class="ng-binding">Name: Age: </my-element>     <table class="table table-hover">       <tbody>         <!-- ngRepeat: p in people -->         <tr ng-repeat="p in people" class="ng-scope">         </tr>         <tr ng-repeat="p in people" class="ng-scope">             </tr>       </tbody>     </table> </div> 

Source HTML

<div ng-controller="MyCtrl">     table1     <table class="table table-hover">         <tr ng-repeat="p in people">             <td>Name: {{ p.name }}</td>             <td>Age: {{ p.age }}</td>         </tr>     </table>     <br/>table2     <table class="table table-hover">         <tr ng-repeat="p in people">             <my-element></my-element>         </tr>     </table> </div> 

Source JS

var app = angular.module('myApp', []);  app.directive('myElement', function () {     return {         restrict: 'E',         template: '<td>Name: {{ p.name }}</td><td>Age: {{ p.age }}</td>'     } });  function MyCtrl($scope) {     $scope.people = [{         name: 'Mike',         age: 20     }, {         name: 'Peter S',         age: 22     }]; } 

Please note the jsFiddle is a trivial example and common sense would lead to just not using directives at all. However, my target code has a much larger template that I want to re-use. I've tried using "ng-include" as well but the result is similar.

like image 420
ravishi Avatar asked Sep 03 '13 20:09

ravishi


People also ask

How do you use NG-repeat in a table?

The ng-repeat directive repeats a set of HTML, a given number of times. The set of HTML will be repeated once per item in a collection. The collection must be an array or an object. Note: Each instance of the repetition is given its own scope, which consist of the current item.

What can I use instead of NG-repeat?

But ng-repeat is not the right thing to use when you have large datasets as it involves heavy DOM manipulations. And you should consider using ng-repeat with pagination. You can consider using transclusion inside a custom directive, to achieve the behavior you are looking for without using ng-repeat.

Does ng-repeat create a new scope?

Each iteration of ng-repeat creates a new child scope, and that new child scope always gets a new property.

Where is the last element in NG-repeat?

$first and $last It's common when using ng-repeat to add specific behavior to the first or last element of the loop, e.g. special styling around the edges. Instead, ng-repeat already supplies you with two ready boolean properties. $first is true for the first element, and $last is true for the last element.


2 Answers

Apply the directive to <tr> like this:

<table class="table table-hover">     <tr my-element blah='p' ng-repeat="p in people"></tr> </table>  app.directive('myElement', function () {     return {         restrict: 'A',         scope:{             ngModel: '=blah'         },         template: '<td>Name: {{ ngModel.name }}</td><td>Age: {{ ngModel.age }}</td>'     } }); 

Working Demo

like image 26
zs2020 Avatar answered Sep 25 '22 22:09

zs2020


<td> is known to behave strangely in directives like this. Instead, use a directive on the parent <tr>. Read more about this issue here: https://github.com/angular/angular.js/issues/1459

<table>     <tr ng-repeat="p in people" my-element></tr> </table> 

Here is how you can further improve your directive so that it is more re-usable.

app.directive('myElement', function () {   return {     scope: {       item: '=myElement'     },     restrict: 'EA',     template: '<td>Name: {{item.name}}</td><td>Age: {{item.age}}</td>'     }; }); 

and pass in the value of item like so:

  <table>     <tr ng-repeat="person in people" my-element="person"></tr>   </table> 

Live Demo

like image 94
m59 Avatar answered Sep 21 '22 22:09

m59