2

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 item.hasMenu == true then apply the directive ?

<ul ng-controller="ListViewCtrl" >
<li contextmenu ng-repeat="item in items">{{item.name}} </li>
</ul>

EDIT

This seems to have worked for me. First the directive.

app.directive('menu',function(){

    return {
        restrict : 'A',

        link : function(scope,element,attrs){

            if(scope.hasMenu){
                        element.contextmenu({
                                        menu:[
                                        {title:"Remove" , "cmd" : "remove"},
                                        {title:"Add" , "cmd" : "add"},
                                        ],
                                        select:function(event,ui){
                                            //alert("select " + ui.cmd + " on" + ui.target.text());
                                            if (ui.cmd ==='remove'){
                                                alert('Remove selected on ' + scope.item);
                                            }
                                            if (ui.cmd ==='add'){
                                                alert("Add selected");
                                            }
                                        }
                        });
            }

        }
    }
    }
);

Then the html

 <ul ng-controller="ListViewCtrl" >
<li menu  ng-repeat="item in items">{{item.name}} </li>
</ul>
3
  • Can you show the contextmenu directive template? Where are you adding the markup for the context menu? Commented Aug 22, 2013 at 13:52
  • I am trying to use github.com/mar10/jquery-ui-contextmenu as the directive. So far I haven't created the directive. This particular plugin has delegate function to filter elements based on the class. I am thinking to use that as the filter criteria but not sure if that'll work. Commented Aug 22, 2013 at 14:02
  • In that case you should be able to use ng-class="{'hasmenu': item.hasMenu}. Commented Aug 22, 2013 at 14:04

3 Answers 3

6

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>
Sign up to request clarification or add additional context in comments.

Comments

1

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

3 Comments

Hi @Christoph. I added the if condition in your applyMenu directive directly into the contextmenu directive. I didn't see any side effects.Yes it is awkward to remove ng-repeat
So you changed the code in a directive which you don't own? That leads to a maintenance nightmare!
No I didn't change the code of directive. I just added a condition that will determine if the element will have a contextmenu or not.
0

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);

            }
        };
    });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.