AngularJS中元素的指令模板唯一ID


70

我有一个指令,可以在一个页面上多次使用。在此指令的模板中,我需要对输入元素使用ID,以便可以将Label“绑定”到它,如下所示:

<input type="checkbox" id="item1" /><label for="item1">open</label>

现在的问题是,一旦多次包含我的指令,ID“ item1”就不再是唯一的,并且标签将无法正常工作(单击时应选中/取消选中该复选框)。

该问题如何解决?有没有一种方法可以为模板分配“名称空间”或“前缀”(例如asp.net使用ctl00 ...- Prefix)?还是我必须在每个id属性中包括一个angular-Expression,它由作用域中的指令ID +一个静态ID组成。就像是:

<input type="checkbox" id="{{directiveID}} + 'item1'" /><label for="{{directiveID}} + 'item1'">open</label>

编辑:

我的指令

module.directive('myDirective', function () {
    return {
        restrict: 'E',
        scope: true, 
        templateUrl: 'partials/_myDirective.html',
        controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
            ...
        } //controller
    };
}]);

我的HTML

<div class="myDirective">
  <input type="checkbox" id="item1" /><label for="item1">open</label>
</div>

Answers:


93

的HTML

    <div class="myDirective">
        <input type="checkbox" id="myItem_{{$id}}" />
        <label for="myItem_{{$id}}">open myItem_{{$id}}</label>
    </div>

10
优雅的解决方案。$ id是$ rootScope为每个子范围提供的唯一范围ID。显然,可以将其用于具有不同范围的任何视图(通常是这种情况)。
塞巴·杜巴卡2015年

7
这是否还应该结合@llan答案中的{{:: expression}}技巧,以避免创建更多手表?
penguin359

7
@ penguin359是的,您也可以一次绑定{{::$id}}。当时我的评论是1.3。
2015年

有趣的是,不可能通过指令的link方法:中的动态选择器查询嵌套元素element.find(`#myItem_ ${scope.$id}`),因为模板尚未编译其动态值……
Nik Sumeiko

有什么解决办法吗?(即Nik的评论)。如果在链接功能中需要使用动态ID修改元素怎么办...没有办法实现?
geoidesic '17

51

更新

Angular 1.3引入了本机懒惰一次性绑定。从角度表达式文档中

一次性绑定

以::开头的表达式被视为一次性表达式。一次性表达式一旦稳定就将停止重新计算,如果表达式结果为非不确定值,则在第一次摘要后会发生(请参见下面的值稳定算法)。

本机解决方案

.directive('myDirective', function() {

    var uniqueId = 1;
    return {
        restrict: 'E',
        scope: true,
        template: '<input type="checkbox" id="{{::uniqueId}}"/>' +
                  '<label for="{{::uniqueId}}">open</label>',
        link: function(scope, elem, attrs) {
            scope.uniqueId = 'item' + uniqueId++;
        }
    }
})

仅绑定一次:

  • 如果您只需要绑定一个值,就不应该使用绑定({{}} / ng-bind)
  • 绑定很昂贵,因为它们使用$ watch。在您的示例中,在每个$ digest上,角度脏都会检查ID的更改,但您只需设置一次即可。
  • 检查此模块:https : //github.com/Pasvaz/bindonce

解:

.directive('myDirective', function() {

    var uniqueId = 1;
    return {
        restrict: 'E',
        scope: true,
        template: '<input type="checkbox"/><label>open</label>',
        link: function(scope, elem, attrs) {
            var item = 'item' + uniqueId++;
            elem.find('input').attr('id' , item);
            elem.find('label').attr('for', item);
        }
    }
})

3
应该提到的是,从1.3开始(当时仍为RC),您可以使用表示法一次进行绑定{{:yourExpression}}
J_A_X 2014年

一次性绑定功能现在记录在这里:docs.angularjs.org/guide/expression#one-time-binding
NoRyb 2014年

我们也可以通过以下方法链接使用此技术:function(scope,elem,attrs){var item ='item'+ uniqueId ++; elem.find('input')。attr('id',item); var element = document.getElementById(item); 现在在元素中,您将获得dom对象,并且您可以执行任何操作:)。动态地设置元素ID的dom的动态操作是非常好的技术!}
Mohammad tanvirul islam 2015年

1
穆罕默德您的榜样尚不清楚。能否请您添加一个答案,使其更清楚地显示您在说什么?
geoidesic

@Mohammadtanvirulislam DOM操作通常不是一个好主意。您为什么要按照您所说的去做?它并没有真正在原始问题/答案中添加任何内容-这是一个完全不同的主题。
NoRyb

2

我们将一个BlockId参数添加到范围,因为例如在Selenium测试中使用了id。它们仍然有可能不是唯一的,但是我们更希望完全控制它们。另一个优点是我们可以为商品提供更具描述性的ID。

指令JS

module.directive('myDirective', function () {
    return {
        restrict: 'E',
        scope: {
            blockId: '@'
        }, 
        templateUrl: 'partials/_myDirective.html',
        controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
            ...
        } //controller
    };
}]);

指令HTML

<div class="myDirective">
  <input type="checkbox" id="{{::blockId}}_item1" /><label for="{{::blockId}}_item1">open</label>
</div>

用法

<my-directive block-id="descriptiveName"></my-directive>

1

除了Ilan和BuriB的解决方案(通用性更好)之外,我还找到了针对特定问题的解决方案,因为我需要标签“ for”属性的ID。而是可以使用以下代码:

<label><input type="checkbox"/>open</label>

以下Stackoverflow-Post已提供帮助:

https://stackoverflow.com/a/14729165/1288552


1
但是,如果您使用的是Bootstrap,则不要使用该方法。因为Bootstrap不允许将输入内容嵌入标签内。
塞巴·杜巴卡2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.