Reputation: 31
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
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
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
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
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
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