【问题标题】:AngularJS - Find Element with attributeAngularJS - 查找具有属性的元素
【发布时间】:2014-01-15 02:43:27
【问题描述】:

我是 AngularJS 的新手。我了解到我可以使用以下查询在 DOM 中查找元素:

var e = angular.element(document.querySelector('#id'));
var e = angular.element(elem.querySelector('.classname'));

这对于按 ID 或 CSS 类名查找元素很有用。但是,我需要能够使用不同的方法找到一个元素。我有一个如下所示的元素:

<div my-directive class='myContainer'>...</div>

我无法查询“myContainer”,因为它被重复使用了多少。出于这个原因,我想找到任何具有“我的指令”属性的元素。如何搜索 DOM 并找到任何使用“my-directive”的元素?

【问题讨论】:

  • 问这个问题表明你并没有完全按照它的意图使用 Angular。你想达到什么目的?
  • 我同意您通常不应该在这种方法中使用 Angular。但是,我需要找到我构建的可能在页面上也可能不在页面上的组件。这就是我尝试搜索 DOM 的原因。
  • 当我遇到完全相同的问题时,我发现了这个问题。对我来说,向元素添加一个 ID 似乎是最简单的。有什么理由不这样做并寻求另一种解决方案?

标签: angularjs


【解决方案1】:

您应该在指令中执行 DOM 操作,而不是查询 DOM 中的元素(这不是很尖锐,请参阅 "Thinking in AngularJS" if I have a jQuery background?)。您可以在链接函数中使用该元素。

所以在你的 myDirective 中

return {
    link: function (scope, element, attr) {
        element.html('Hello world');
    }
}

如果您必须在指令之外执行查询,则可以在现代浏览器中使用 querySelectorAll

angular.element(document.querySelectorAll("[my-directive]"));

但是你需要使用 jquery 来支持 IE8 和向后

angular.element($("[my-directive]"));

或编写您自己的方法,如此处所示Get elements by attribute when querySelectorAll is not available without using libraries?

【讨论】:

  • 我对这种方法很熟悉。但是,在这种情况下,我确实需要查询 DOM。有没有办法做到这一点?
  • 小心angular.element(document.querySelectorAll())。这从文档根目录搜索,这可能不是您想要的。我在下面的回答显示了如何使用控制器在元素范围内查找元素,优秀的开发人员会尝试避免这种情况,但有时却做不到。 stackoverflow.com/a/24275151/1450294
【解决方案2】:

你没有说明你在哪里寻找元素。如果它在控制器的范围内,则有可能,尽管您会听到合唱不是“角度方式”。合唱是对的,但有时,在现实世界中,这是不可避免的。 (如果您不同意,请联系我们——我有一个挑战。)

如果你将$element 传递给控制器​​,就像你传递$scope 一样,你可以使用它的find() 函数。请注意,在 Angular 中包含的 jQueryLite 中,find() 只会按名称定位标签,而不是属性。但是,如果您在项目中包含成熟的 jQuery,则可以使用 find() 的所有功能,包括按属性查找。

所以,对于这个 HTML:

<div ng-controller='MyCtrl'>
    <div>
        <div name='foo' class='myElementClass'>this one</div>
    </div>
</div>

这个 AngularJS 代码应该可以工作:

angular.module('MyClient').controller('MyCtrl', [
    '$scope',
    '$element',
    '$log',
    function ($scope, $element, $log) {

        // Find the element by its class attribute, within your controller's scope
        var myElements = $element.find('.myElementClass');

        // myElements is now an array of jQuery DOM elements

        if (myElements.length == 0) {
            // Not found. Are you sure you've included the full jQuery?
        } else {
            // There should only be one, and it will be element 0
            $log.debug(myElements[0].name); // "foo"
        }

    }
]);

【讨论】:

  • 为此,您需要依赖完整的 jQuery 而不是嵌入在 AngularJS 中的 jQueryLite。对于那些(我)不愿意依赖 jQuery 但仍在学习 jQueryLite 局限性的人来说,不说明这种区别可能会令人沮丧
  • 我很抱歉给您带来的挫败感。我猜我正在从事的项目确实包含 jQuery——我不认为它包含,但现在我已经研究过它,我发现文档声明 find() 仅在 jQueryLite 中按名称搜索标签。我会相应地更新我的答案。
  • 考虑到在Angular编程中,我们不应该直接操作DOM,这是在控制器中使用$element的反模式吗?
  • @gm2008:你可以这样说。答案中的第二句和第三句是我的反驳。
【解决方案3】:

您的用例不清楚。但是,如果您确定需要它基于 DOM,而不是模型数据,那么这是一个指令引用所有元素的一种方式,并在其上指定了另一个指令。

方式是子指令可以require父指令。父指令可以公开一个允许直接指令向父指令注册其元素的方法。通过这个,父指令可以访问子元素。因此,如果您有这样的模板:

<div parent-directive>
  <div child-directive></div>
  <div child-directive></div>
</div>

那么指令可以这样编码:

app.directive('parentDirective', function($window) {
  return {
    controller: function($scope) {
      var registeredElements = [];
      this.registerElement = function(childElement) {
        registeredElements.push(childElement);
      }
    }
  };
});

app.directive('childDirective', function() {
  return {
    require: '^parentDirective',
    template: '<span>Child directive</span>',
    link: function link(scope, iElement, iAttrs, parentController) {
      parentController.registerElement(iElement);
    }
   };
});

您可以在 http://plnkr.co/edit/7zUgNp2MV3wMyAUYxlkz?p=preview 看到这一点

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-04-10
    • 2013-07-03
    • 2021-10-19
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    • 2013-02-04
    • 2013-04-24
    相关资源
    最近更新 更多