【问题标题】:How to pass a DOM element to "ng-disabled"如何将 DOM 元素传递给“ng-disabled”
【发布时间】:2016-08-03 21:27:13
【问题描述】:

全部,

如何将当前 DOM 元素传递给 Angular 指令“ng-disabled”?

我知道在 Angular 中弄乱 DOM 是不好的做法。但我想不出另一种简单的方法来做到这一点。这是我的问题:

我有一个按钮,点击时会更新范围变量:

<button ng-click="target_model.display_detail=true">click me</button>

在我的模板的其他地方有代码监视“target_model.display_detail” - 如果它是真的,它会显示一个模态对话框,其中包含一个 Angular 指令,该指令从服务器获取一些数据并填充一个表单 其中包括另一个像上面那个按钮

我正在使用的数据结构可能是递归的;有大量嵌套的“target_models”。因此,模态对话框中的按钮可以指向已经创建了表单的 target_model。在这种情况下,我只想禁用该按钮。我想做一些类似的事情:

<button ng-disabled="ancestor_model_exists(the_current_element, target_model.some_unique_id)">click me</button>

其中“ancestor_model_exists”是一个检查 DOM 以查看是否存在具有特定 id 的祖先元素的函数。但是我怎么知道从哪个元素开始呢?

【问题讨论】:

    标签: javascript angularjs dom


    【解决方案1】:

    您正在以命令方式处理 DOM 操作 - jQuery 方式,而不是声明方式 - Angular 方式。

    DOM 操作很好……在指令内部。您不会在控制器中执行此操作,您可能在其中定义了该功能。

    当你有机会时,试着在沙盒中通过 0 次调用 $ 来迫使你学习如何以 Angular 的方式做事——不是因为它绝对“更好”——它只是一般无论如何,最好先学习工具包和推荐的方法,然后再按照自己的方式进行操作。

    这应该做你想做的事,除了可能搜索多个祖先之外(但如果你需要,我会提到如何做到这一点):

    https://plnkr.co/edit/7O8UDuqsVTlH8r2GoxQu?p=preview

    JS

    app.directive('ancestorId', function() {
      return {
        restrict: 'A',
        controller: 'AncestorIdController',
        require: ['ancestorId'],
        link: function(scope, element, attrs, controllers) {
          var ancestorIdController = controllers[0];
    
          // If you wanted to use an expression instead of an 
          // interpolation you could define an isolate scope on this 
          // directive and $watch it.
          attrs.$observe('ancestorId', function(value) {
            ancestorIdController.setId(value);
          });
        }
      }
    });
    
    app.controller('AncestorIdController', function() {
      this.getId = _getId;
      this.setId = _setId;
    
      var id;
    
      function _getId() {
        return id;
      }
    
      function _setId(value) {
        id = value;
      }
    });
    
    app.directive('disableForAncestorId', function() {
      return {
        restrict: 'A',
        require: ['?^ancestorId'],
        link: function(scope, element, attrs, controllers) {
          var ancestorIdController = controllers[0];
    
          // Check to make sure the ancestorId is a parent.
          if (ancestorIdController) {
            scope.$watch(function() {
              var watch = {
                target: ancestorIdController.getId(),
                actual: attrs.disableForAncestorId
              };
              return watch;
    
            }, function(value) {
              if (value.target === value.actual) {
                element.attr('disabled', 'disabled');
              } else {
                element.removeAttr('disabled');
              }
            }, true /* Deep watch */ );
          }
        }
      }
    });
    

    HTML

    <!-- The simple happy path. -->
    <div ancestor-id="A">
      <button disable-for-ancestor-id="A">'A' === 'A' ?</button>
    </div>
    
    <!-- require will match the 'B' before the 'A' because it's closer.
     if you need to match any parent you could use a third coordinating
     directive. -->
    <div ancestor-id="A">
      <div ancestor-id="B">
        <button disable-for-ancestor-id="A">'B' === 'A' ?</button>
      </div>
    </div>
    
    <!-- require lets you freely change the DOM to add extra elements separating
    you from what you're looking for.-->
    <div ancestor-id="B">
      <div>
        <div>
          <button disable-for-ancestor-id="B">'B' === 'B' ?</button>
        </div>
      </div>
    </div>
    
    <!-- It doesn't blow up if it doesn't find an ancestorId. -->
    <div>
      <button disable-for-ancestor-id="B">'B' === undefined ?</button>
    </div>
    
    <br>
    Dynamic AncestorId test (it will be disabled if the text fields are equal):
    <br>
    Target AncestorId <input ng-model="targetAncestorId">
    <br>
    Actual Ancestor <input ng-model="actualAncestorId">
    <!-- It doesn't blow up if it doesn't find an ancestorId. -->
    <div ancestor-id="{{ targetAncestorId }}">
      <button disable-for-ancestor-id="{{ actualAncestorId }}">'{{ actualAncestorId }}' === '{{ actualAncestorId }}' ?</button>
    </div>
    

    【讨论】:

      【解决方案2】:

      它永远不会失败...在 Stack Overflow 上发布问题总是让我在几分钟后意识到答案。

      下面的代码让我非常接近:

      template.html:

      <button ng-click="display_if_ancestor_model_exists($event, target_model)">click me</button>
      

      app.js:

      $scope.display_if_ancestor_model_exists = function($event, target_model) {
        var ancestor_form = $($event.target).closest("#" + target_model.some_unique_id);
        if (ancestor_form.length) {
          /* don't show the modal-dialog */
          display_msg("This form already exists!");
        }
        else {
          target_model.display_detail = true;
        }
      };
      

      当然,我宁愿禁用该按钮,但我现在可以使用此解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-10-04
        • 1970-01-01
        • 1970-01-01
        • 2018-10-28
        • 2017-04-16
        • 2021-01-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多