0

I have an angular application which uses an ng-repeat-start to display some dynamic information.

<div>
  <table>
    <tbody>
      <tr my-directive ng-repeat="data in vm.data">
        <td ng-bind="data.id"></td>    
        <td ng-bind="data.id"></td>    
      </tr>
        <tr ng-repeat-end>
        <td>extrarow</td>
      </tr>
    </tbody>
  </table>
</div>

I also built a directive which I want to use to apply a class to the whole tr depending on the value of some of the data. I wanted to use link to do that instead of using a $watch.

As the itself can contain many inside, I wanted to use transclude to do this. I don´t want the tag to be inserted in my table as this breaks all my styles, so I have to do this manually, something like this:

function myDirective() {
    return {
       transclude: true,
       scope: {},
       link: function($scope, $element, $attrs, $ctrl, $transclude) {
          var cloned = $transclude();
          $element.append(cloned);              
       }
    }
}

The problem is this is not working as expected. The cloned object is only being appended to the last row of the ng-repeat. It's probably due to the $element object, but I'm not sure about it.

I reproduced the problem in this jsfiddle.

Any ideas on where the problem is? Many thanks.

David
  • 3,364
  • 10
  • 41
  • 84
  • Not sure what you're trying to accomplish, but remove the transclude: true from your directive, https://jsfiddle.net/tf9s7skq/1/ If you're simply trying to set the TR class based on the data, use element.css() - transclusion looks like the wrong thing to do here. – RamblinRose Jun 03 '16 at 12:40
  • Not sure about what transclude:false does, but you're right, all my elements are displayed, but also an error as $transclude is not a function anymore. Also, the last extrarow is displayed only for the last row. Also, this is a simple example, but in my app I have a really big table with many cells per row; that's why I use transclude, I don´t want to lose those cells when applying the directive. – David Jun 03 '16 at 12:55
  • Ok, @RamblinRose, I just realize that you're right, as I don´t have a template I don´t need to use transclude, it's much easier. Thanks – David Jun 03 '16 at 13:24

4 Answers4

1

Setting transclude to false in your directive will give you the whole list.

Tom Shen
  • 1,045
  • 3
  • 11
  • 29
1

I am befuddled why you're requiring transclude. I think this is what you're looking for; however I have to say I am not convinced about the economy of $observe over $watch here.

For $observe, I've added the following to the TR:

 <tr my-directive data-value="{{data.id}}" ng-repeat="data in vm.data"> 

and the directive demonstrates the class change on some condition.

function myDirective() {
      return {
        link: function($scope, element, attrs) {
          attrs.$observe('value', function(val) {
            if (val && val == "9.2")
              element.addClass("myClass");
            else
              element.removeClass("myClass");
          });              
       }
    }
  }
RamblinRose
  • 4,883
  • 2
  • 21
  • 33
  • Thanks, @RamblinRose, you were right; previously I was using a template and I had to use transclude; I just didn´t realize that in this case I didn´t have to anymore. – David Jun 04 '16 at 09:47
0

If you just want to add a class depending on your content you can use ng-class

<td ng-bind="data.id" ng-class="{'myClass': data.id > 4}"></td>  

EDIT

You can use an one time binding, then you don't have to many $watchers

<td ng-bind="data.id" ng-class="::{'myClass': data.id > 4}"></td> 
Simon Schüpbach
  • 2,625
  • 2
  • 13
  • 26
  • I know, I don´t want to use ng-class. I have to repeat something like this many times in my table and this adds many $$watchers. I want to use $observe to do this, and thus I have to use transclude. – David Jun 03 '16 at 12:46
  • No, my class is dynamic, and also the data.id that I'm using, so one-time bind is not an option. – David Jun 03 '16 at 12:52
0

If you would want to run another custom ng-repeat directive that you have written, you can by setting a different priority to your ng-repeat directive. Lower priority than default ng-repeat directive will cause it to run after default ng-repeat.

I have updated your jsFiddle with a sample, https://jsfiddle.net/1x08vxpm/15/

angular.module('app', [])

.controller('Controller', Controller)    
.directive('ngRepeat', ngRepeat);

function ngRepeat() {
    return {    
       priority: 0,
       scope: {},
       link: function($scope, $element, $attrs) {
          $element.css('color', 'red');
       }
    }
}
Muthukannan Kanniappan
  • 2,080
  • 1
  • 16
  • 18
  • I want to be able to use the directive in a , to apply a style for rows, but also in a , for single cells, so I can´t use this one. It's a good idea for other scenarios, though. – David Jun 03 '16 at 13:00