AngularJS directive only when the condition is true

只愿长相守 提交于 2019-12-19 04:48:51

问题


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>

回答1:


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>



回答2:


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:


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

            }
        };
    });


来源:https://stackoverflow.com/questions/18382331/angularjs-directive-only-when-the-condition-is-true

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!