从指令包装源元素的更好方法

Better way to wrap a source element from a Directive?

本文关键字:更好 方法 元素 指令 包装      更新时间:2023-09-26

我正在编写一个指令(使用AngularJS 1.2.0-rc2,如果这很重要的话(,该指令在<input>中添加了一个"清除"按钮(想想浏览器为<input type="search">元素添加的"x"按钮(。

由于"清除"按钮是从指令中注入的并且绝对定位,因此我想将现有<input>和新添加的"清除"按钮都包含在包装器元素中,该包装元素具有position: relative以确保正确定位"清除"按钮。

声明的 HTML 如下所示:

<input type="text" id="myField" data-ng-model="someModel" data-search>

到目前为止,我拥有的指令:

angular.module('myApp', []).directive('search', function() {
  var
    clear = angular.element('<a href role="button" class="btn x" style="display:none">&times;</a>'),
    wrapper = angular.element('<div style="position: relative"></div>');
  return {
    restrict: 'A',
    link: function( scope, element, attrs ) {
      element.wrap(wrapper.append(clear));
      // more code that's not relevant to my question
    }
  };
});

我最终得到的 HTML 是

<div style="position: relative">
  <a href role="button" class="btn x" style="display: none">&times;</a>
  <input type="text" id="myField" data-ng-model="someModel" data-search>
</div>

这就是我所追求的,但我想理想地模板化两个新元素并将 DOM 操作从我的 link 函数中抽象出来。

我觉得使用replace/templatetransclude 选项之一或两者可能有更好的方法,但我不确定如何保留和使用源元素(及其所有属性和数据绑定(与这些选项中的任何一个。

另请注意,即使我的示例在源元素上定义了ng-model,也应将其视为可选。我还想将指令限制为属性(restrict: 'A'(。

Transclusion可能是你要找的。下面是一些更新的代码。

模板:

<div style="position: relative">
  <a href role="button" class="btn x" style="display: none">&times;</a>
  <div ng-transclude></div>
</div>

命令:

angular.module('myApp', []).directive('search', function() {
  return {
    restrict: 'A',
    replace: true,
    transclude: true,
    // template: '', // string template of the HTML above, or better yet
    templateUrl: '', // relative URL of an HTML file containing the above template
  };
});

.HTML:

<div data-search>
  <input type="text" id="myField" data-ng-model="someModel">
</div>

您应该在指令中只使用模板或模板 URL 之一,我会倾向于模板 URL,因为我讨厌字符串模板。

如果需要更多逻辑,您仍然可以包含链接函数。

replace 属性将完全替换应用该元素的现有 DOM 元素,而省略此属性将保留该元素并将模板放入其中。由您希望如何配置。

考虑一下,如果你这样做:

transclude: 'element'

你可以在HTML中这样做:

<input type="text" id="myField" data-ng-model="someModel" data-search>

在我看来,设计可重用组件的更好方法是隔离作用域和指令控制器。在您的情况下,我没有看到您的逻辑,因此我将仅使用隔离范围使其变得简单。

您的模板文件:

<div style="position: relative">
  <a href role="button" class="btn x" style="display: none">&times;</a>
  <input type="text" id="myField" data-ng-model="model">
</div>

.JS:

angular.module('myApp', []).directive('search', function() {
  return {
    restrict: 'E',
    scope:{
      model:"=model"
    },
    link: function( scope, element, attrs ) {
      // more code that's not relevant to my question
    },
    templateUrl:url-to-your-template
  };
});

使用它:

<search model="someModel"/>

或者只是:

<search />

如果需要将其用作属性,请尝试:

.JS:

angular.module('myApp', []).directive('search', function() {
  return {
    restrict: 'A',
    scope:{
      model:"=model"
    },
    replace:true,
    link: function( scope, element, attrs ) {
      // more code that's not relevant to my question
    },
    templateUrl:url-to-your-template
  };
});

使用它:

<div search model="someModel"/>

或只是:

<div search />