Arthur Stepanyuk
Arthur Stepanyuk

Reputation: 31

Conditionally add attribute directive to the ng-repeat

I would like to know if its possible to add attribute directive to some elements inside of ng-repeat. I have tried checking CSS class or id but without luck.

Example code

class ItemNavigation {

  constructor(NavigationService ) {
      this.NavigationService = NavigationService;
  }

}

angular.module('core')
  .directive('itemNavigation', function ($timeout) {
    return {
      bindToController: true,
      scope: {
        itemId: '='
      },
      controllerAs: '$ctrl',
      restrict: 'A',
      link: function(scope, elem, attrs, ctrl) {
        $timeout(() =>{
          elem.bind('click', function() {
            let noRedirect = $(this).hasClass('no-redirect');
            // this approch doesnt work it never finds class
            if(!noRedirect) return ctrl.NavigationService.goToItemDetails(ctrl.itemId)        
          })
        })
       ;
      },
      controller: ItemNavigation 
    };
  });

Example of html

    <tr ng-repeat="item in $data track by item.id" item-navigation item-id="item.id">
      <td class="no-redirect">I dont want my directive to work here</td>
      <td>I want my directive to work here</td>
      <td>I want my directive to work here</td>
      <td class="no-redirect">I dont want my directive to work here</td>
      <td>I want my directive to work here</td>
      <td>I want my directive to work here</td>
    </tr>

I would be grateful for any help

Upvotes: 2

Views: 877

Answers (4)

Andrew Svorak
Andrew Svorak

Reputation: 26

You could add event target to your code it also will solve issues if you need to copy text from tds and your directive will work only when you click outside of text. Also you can remove timeout from your code.

Please check following changes

   <table>
      <tr ng-repeat="one in data" row-navigation item-id="one.id"
      class="table table-striped table-bordered">
        <td class="no-redirect">Dont alert when i click here</td>
        <td><span class="no-redirect">Dont when i click on this text only, but works in TD element</span></td>
        <td>Alert when i click here</td>
      </tr>
    </table>

and your linking function should look like this

 app.directive('rowNavigation', function () {
    return {
      scope: {
        itemId: '='
      },
      controllerAs: 'ctrl',
      restrict: 'A',
      link: function(scope, elem, attrs, ctrl) {

          elem.bind('click', function(event) {
            var noRedirect = $(event.target).hasClass('no-redirect');
            // it will work now
            if(!noRedirect) alert(ctrl.itemId)        
          })

      },
      controller: function($scope) {
        this.itemId = $scope.itemId
       } 
    };
  });

Upvotes: 1

georgeawg
georgeawg

Reputation: 48968

If the goal is to change click behavior on child nodes, just use the ng-click directive:

<table>
<!--       Also please dont use stop Event.stopPropagation() 
           as it breaks some of flow on mobile devices in my application 
-->
  <tr ng-repeat="one in data" ng-click="alert(one.id)"
  class="table table-striped table-bordered">
    <td class="no-redirect" ng-click="dontAlert($event)">
        Dont alert when i click here</td>
    <td>Alert when i click here</td>
    <td>Alert when i click here</td>
  </tr>
</table>

And to avoid using event.stopPropagation, have the child click handler set a flag for the parent click handler:

var dontAlertFlag = false;

$scope.alert = function(id) {
    !dontAlertFlag && alert(id);
    dontAlertFlag = false;
};
$scope.dontAlert = function(event) {
    //event.stopPropagation();
    dontAlertFlag = true;
    console.log(event);
} 

In the above example, when the child element is clicked, the child click handler sets the dontAlertFlag to true. The parent click handler uses the flag and then resets it.

The DEMO on PLNKR


Update

The code can be simpified by using the event.target property:

<table>
<!--       Also please dont use stop Event.stopPropagation() 
           as it breaks some of flow on mobile devices in my application 
-->
  <tr ng-repeat="one in data" ng-click="alert(one.id,$event)"
  class="table table-striped table-bordered">
    <td class="no-redirect">
        Dont alert when i click here</td>
    <td>Alert when i click here</td>
    <td>Alert when i click here</td>
  </tr>
</table>

JS

   $scope.alert = function(id,event) {
        var $target = angular.element(event.target);
        console.log($target);
        if (!$target.hasClass("no-redirect")) {
             alert(id);
        }
        console.log(event);
    };

In the above example, the click handler checks the target to see if it has a class called no-redirect. If the target doesn't have that class, it fires the alert.

The DEMO on PLNKR

Upvotes: 1

RL89
RL89

Reputation: 1916

I think you can; As per my understanding, you want to put a condition for even rows only.

One easy solution: Put a condition using $index inside ng-repeat rows.

  <tr ng-repeat="item in $data track by item.id" item-navigation item-id="item.id">
  <td class="no-redirect" ng-if="$index % 3 == 0">I dont want my directive to work here</td>
  <td class="no-redirect" ng-if="$index % 2 == 0">I want my directive to work here</td>

</tr>

These are the changes you need to make in your directive.

   app.directive('rowNavigation', function ($timeout) {
    return {
      scope: {
    itemId: '='
  },
  controllerAs: 'ctrl',
  restrict: 'A',
  link: function(scope, elem, attrs, ctrl) {
      $timeout(function() {
      elem.bind('click', function() {
         console.log(ctrl)
         alert(ctrl.itemId);
      })
   });
  },
  controller: function($scope) {
    this.itemId = $scope.itemId
   } 
};
});

And in you ng-repeat, change it to

 <tr ng-repeat="one in data"  item-id="one.id"
  class="table table-striped table-bordered">
    <td  class="no-redirect">Dont alert when i click here</td>
    <td row-navigation item-id="one.id">Alert when i click here</td>
    <td row-navigation item-id="one.id">Alert when i click here</td>
  </tr>

Hope this helps.

Upvotes: 2

Searching
Searching

Reputation: 2279

You seem to be binding it to the window object when checking for hasClass instead of the element itself.

let noRedirect = $(this).hasClass('no-redirect'); // update this
let noRedirect = elem.hasClass('no-redirect'); // this should help

Can you console.log it to verify ? let us know.

Upvotes: 1

Related Questions