I am going to have a contextmenu directive in ng-repeat items. Based on whether a condition is true, the directive should be applied. How do I put a condition like only when
Can you do something like this, using ng-if
?
<ul ng-controller="ListViewCtrl" >
<li ng-repeat="item in items">
<span>{{item.name}}</span>
<div contextmenu ng-if="item.hasMenu"></div>
</li>
</ul>
Here are the docs for ng-if.
EDIT: If you are driving the context menu off of a class, you should be able to do this:
<ul ng-controller="ListViewCtrl" >
<li ng-class="{'hasmenu': item.hasMenu}" ng-repeat="item in items">{{item.name}} </li>
</ul>
I think this is pretty tricky if you don't want to change your DOM structure. If you could just place your contextmenu
directive on a sub DOM node inside the <li>
things would be a lot easier.
However, let's assume you can't do that and let's also assume that you don't own the contextmenu
directive so that you can't change it to your needs.
Here is a possible solution to your problem that might be a bit hackish (actually I don't know!)
'use strict';
angular.module('myApp', [])
.controller('TestController', ['$scope', function($scope) {
$scope.items = [
{name:1, hasMenu: true},
{name:2, hasMenu: false },
{name:3, hasMenu: true}
];
}])
.directive('contextmenu', function(){
return {
restrict: 'A',
link: function(scope, element){
element.css('color', 'red');
}
}
})
.directive('applyMenu', ['$compile', function($compile){
return {
restrict: 'A',
link: function(scope, element){
if (scope.item.hasMenu){
//add the contextmenu directive to the element
element.attr('contextmenu', '');
//we need to remove this attr
//otherwise we would get into an infinite loop
element.removeAttr('apply-menu');
//we also need to remove the ng-repeat to not let the ng-repeat
//directive come between us.
//However as we don't know the side effects of
//completely removing it, we add it back after
//the compile process is done.
var ngRepeat = element.attr('ng-repeat');
element.removeAttr('ng-repeat');
var enhanced = $compile(element[0])(scope);
element.html(enhanced);
element.attr('ng-repeat', ngRepeat);
}
}
}
}]);
I faked the contextmenu
directive to just change the color
to red
just so that we can see it's taking place.
Then I created an apply-menu
attribute directive. This directive than checks if the hasMenu
property is true and if so hooks in and adds the contextmenu
directive and does a manual $compile
process.
However, what worries me a bit about this solution is that I had to temporally remove the ng-repeat
directive (and also the apply-menu
directive) to get the $compile
process to act the way we want it to act. We then add the ng-repeat
directive back once the $compile
has been made. That is because we don't know the side effects of removing it entirely from the resulting html. This might be perfectly valid to do, but it feels a bit arkward to me.
Here is the plunker: http://plnkr.co/edit/KrygjX
You can do this way
angularApp.directive('element', function($compile) {
return {
restrict: 'E',
replace: true,
transclude: true,
require: '?ngModel',
scope: 'isolate',
link: function($scope, elem, attr, ctrl) {
$scope.isTrue = function() {
return attr.hasMenu;
};
if($scope.isTrue())
//some html for control
elem.html('').show();
else
//some html for control
elem.html('').show();
$compile(elem.contents())($scope);
}
};
});