javascript - 如何创建一个指令,根据条件在目标元素上添加 ng-class 和 ng-disabled?

标签 javascript angularjs

我有以下代码:

app.directive "ngDisableOnVar", ($compile) ->
  restrict: "A"
  terminal: true
  priority: 1000
  replace:false
  scope: {}
  compile: compile = (element, attrs) ->
    cattr = attrs["ngDisableOnVar"]
    element.attr("ng-class", "{'disabled': !#{cattr}}")
    element.attr("ng-disabled", "!#{cattr}")
    element.removeAttr("ng-disable-on-var")
    pre: preLink = (scope, iElement, iAttrs, controller) ->

    post: postLink = (scope, iElement, iAttrs, controller) ->
      $compile(iElement)(scope)

我试图将代码基于给定的答案 here .基本上,我想要以下内容:

<input ngDisableOnVar="someScopeVariable>

并将其替换为以下内容:

<input ng-class="{'disabled': !someScopeVariable}" ng-disabled="!someScopeVariable">

出了点问题,因为即使我将它们应用于我的元素,它们也始终处于禁用状态,即使范围变量的计算结果为真。我做错了什么?

编辑: 我创建了一个 plunker,其中前 2 个按钮是使用 ng-class 和 ng-disabled 创建的,其他 2 个按钮应该通过使用指令对它们应用相同的东西。

这是具有共享范围的 plunker 版本:http://plnkr.co/edit/TebCQL20ubh5AgJ6nMIl?p=preview

这是没有共享范围的:http://plnkr.co/edit/CPm55MrHA8z6Bx4GbxoN?p=preview

问题是,没有共享范围的不会更新。我怎样才能使它们更新,并使条件取决于作为参数传递的变量?

编辑#2: 我开始相信范围共享是这两个按钮应该起作用的正确方式,而不是创建一个将两个按钮封装在其中的新指令。虽然不能 100% 确定。

最佳答案

我会同意您的编辑#2,因为它们是相关的。如果我们将它们创建为单独的元素,我们需要以某种方式将相关元素传递给每个元素 => 当我们单击 1 个按钮时,我们会更新自身以及相关元素。

我在这里修改了您的第一种方法以使其起作用:http://plnkr.co/edit/KgYIlATiw9xzTEZt9Jv1?p=preview

在这个例子中,我必须将相关元素传递给每个指令,这样当我们点击时我们可以更新自身和相关元素:

related-element="btnForward"

我在指令中做了一些修改:

scope: {
      reactOn: "=", //use property binding instead of function binding
      relatedElement:"@" 
    },
link: function(scope, element, attrs) { 
      scope.toggle = function(){
        scope.reactOn = !scope.reactOn;//toggle current element
        var relatedScope = $("#"+scope.relatedElement).scope();//get related element's scope and toggle it
        relatedScope.reactOn = !relatedScope.reactOn;
      }
      //var cattr = attrs.ngDisableReactOn;
      element.attr("ng-class", "{'disabled': !reactOn}"); //Use reactOn instead as this is the property of current scope
      element.attr("ng-disabled", "!reactOn");
      element.attr("ng-click", "toggle()"); 
      element.removeAttr("ng-disable-react-on");
      $compile(element)(scope);
    }

我们不需要让事情变得复杂。只需创建一个普通指令来包裹 2 个按钮。

myApp.directive("ngDisableReactOn", function($compile) {
  return {
    restrict: "A",
    templateUrl:"ngDisableReactOn.html",
    scope: {
      can_go_back: "@"
    },
    link: function(scope, element, attrs) { 
      scope.goBack = function(){
          scope.can_go_back = false;
      }

      scope.goFwd = function(){
          scope.can_go_back = true;
      }
    }
  }
});

模板:

<input type="button" value="go back" ng-click="goBack()"  ng-class="{'disabled': !can_go_back}" ng-disabled="!can_go_back">
<input type="button" value="go fwd"  ng-click="goFwd()"   ng-class="{'disabled': can_go_back}" ng-disabled="can_go_back">

DEMO

另一种解决方案是创建父指令作为容器。这是我最喜欢的解决方案。使用这种方法,您可以自由更改指令的内部内容,例如添加更多按钮、更多文本……(不需要对模板进行硬编码)父指令用作管理器确保一次只有 1 个活跃的 child :

myApp.directive("ngDisableReactOnContainer", function() { //Container directive to manage all child directives
  return {
    restrict: 'EA',
    replace: true,
    transclude: true,//Use transclusion to move inner content to the template
    template: '<div ng-transclude></div>',
    controller: function() {
      var children = []; 
      this.selectChild = function(activeChild) { //ensure that only 1 child is active at a time
        activeChild.active = true;
        angular.forEach(children, function(child) {
          if (child != activeChild) {
            child.active = false;
          }
        });
      }

      this.addChild = function(child) {
        children.push(child);
      }
    }
  };
});

myApp.directive("ngDisableReactOn", function($compile) {
  return {
    restrict: "A",

    scope:{
      active:"@"
    },

    require: '^?ngDisableReactOnContainer',
    link: function(scope, element, attrs, controller) {

      scope.active = scope.active === 'true';

      controller.addChild(scope);//register itself with the container

      scope.select = function(){//When this element is clicked, inform the container to toggle all children accordingly.
         controller.selectChild(scope);
      }

      //Add ng-class and ng-disabled based on your requirement.
      element.attr("ng-class", "{'disabled': active}"); //Use active instead as this is the property of current scope
      element.attr("ng-disabled", "active");
      element.attr("ng-click", "select()"); 
      element.removeAttr("ng-disable-react-on");
      $compile(element)(scope);
    }
  }
});

使用这些指令很简单:

<div ng-disable-react-on-container>
    <input ng-disable-react-on type="button" value="button 1" active="true" >
    <input ng-disable-react-on type="button" value="button 2" >
    <input ng-disable-react-on type="button" value="button 3" >
</div>

DEMO

关于javascript - 如何创建一个指令,根据条件在目标元素上添加 ng-class 和 ng-disabled?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21484641/

相关文章:

javascript - $rootScope 在 AngularJs 中不与我一起工作

javascript - 在 ng-repeat Angular js 中获取 html 元素

javascript - React 和 google-maps-react。不显示信息窗口

javascript - 如何从 angular.element [jqLit​​e] 更改第二/第三等标签的背景

javascript - 警告 : Cannot update during an existing state transition (such as within `render` or another component's constructor)

javascript - AngularJS 函数以表单调用自身

javascript - jQuery fadeIn fadeOut 效果问题

javascript - 禁用安全搜索的 Bing 图像搜索 URL

javascript - AngularJS 混淆

javascript - $ionicPlatform.ready(function() 中的 Ionic $state.go