在这种情况下我应该使用隔离范围吗?

时间:2015-04-03 02:44:30

标签: angularjs

我正在实现自定义输入窗口小部件。真正的代码更复杂,但通常看起来像这样:

app.directive('inputWidget', function () {
  return {
      replace:true,
      restrict: 'E',
      templateUrl:"inputWidget.html",
      compile: function (tElement, tAttributes){
          //flow the bindings from the parent.
          //I can do it dynamically, this is just a demo for the idea
          tElement.find("input").attr("placeholder", tAttributes.placeholder);
          tElement.find("input").attr("ng-model", tElement.attr("ng-model"));
      }
    };
});

inputWidget.html:

<div>
  <input />
  <span>
  </span>
</div>

使用它:

<input-widget placeholder="{{name}}" ng-model="someProperty"></input-widget>

使用上面的代码正确显示占位符,因为它使用了父级的相同范围:http://plnkr.co/edit/uhUEGBUCB8BcwxqvKRI9?p=preview

我想知道是否应该使用隔离范围,如下所示:

app.directive('inputWidget', function () {
      return {
          replace:true,
          restrict: 'E',
          templateUrl:"inputWidget.html",
          scope : {
              placeholder: "@"
              //more properties for ng-model,...
          }
      };
 });

有了这个,该指令不与父级共享相同的范围,这可能是一个好的设计。但问题是这个隔离范围定义会很快变得混乱,因为我们在其上添加与DOM相关的属性(占位符,类型,必需,......)以及每次我们需要申请时一个新指令(输入窗口小部件上的自定义验证),我们需要在隔离范围上定义一个属性,以充当中间人

我想知道始终在指令组件上定义隔离范围是否是个好主意。

在这种情况下,我有3个选项:

  • 使用与父级相同的范围。
  • 如上所述使用隔离范围。
  • 使用隔离范围,但不要将与DOM相关的属性绑定到它,以某种方式直接从父级流动与DOM相关的属性。我不确定这是不是一个好主意,我也不知道该怎么做。

请建议,谢谢。

2 个答案:

答案 0 :(得分:2)

如果输入窗口小部件配置很复杂,我会使用options属性,并使用一个独立的范围来使属性显式和强制:

<input-widget options="{ placeholder: name, max-length: 5, etc }" 
   ng-model="name"></input-widget>

如果您有选项模型和ngModel,则无需流动任何DOM属性:

app.directive('inputWidget', function () {
  return {
      replace:true,
      restrict: 'E',
      templateUrl:"inputWidget.html",
      scope: { options:'=', ngModel: '='}

    };
});

在您的模板中,您可以像往常一样将属性绑定到$ scope视图模型:

<div>
  <input placeholder="{{options.placeholder}}" ng-model="ngModel"/>
  <span>
    {{options}}
  </span>
</div>

Demo

就个人而言,在开发重用时,我更喜欢使用属性作为配置指令的方法,并使用隔离范围使其更具模块性和可读性。它的行为更像是一个组件,通常不需要外部环境。

但是,有时候我发现有子/继承范围的指令很有用。在这种情况下,我通常会要求&#39;用于提供上下文的父指令。这对指令一起工作,因此较少的属性必须流向子指令。

答案 1 :(得分:1)

这不是一个非常微不足道的问题。这是因为人们可能对模板化元素有任意指令,这些指令可能是<input>,并且正确的解决方案应该确保:1)这些指令只编译和链接一次,2)编译实际{{1 } - 不是<input>

出于这个原因,我建议使用实际的<input-widget>元素,并添加<input>指令作为属性 - 该指令将应用模板,而实际的inputWidget元素将承载其他指令(如<input>ng-model,自定义验证器等)可以对其进行操作。

ng-required

<input input-widget ng-model="someProp" placeholder="{{placeholder}}" ng-required="isRequired" p1="{{name}}" p2="name"> 将使用两个编译过程(在inputWidget之后建模):

ngInclude

模板(app.directive("inputWidget", function($templateRequest) { return { priority: 400, terminal: true, transclude: "element", controller: angular.noop, link: function(scope, element, attrs, ctrl, transclude) { $templateRequest("inputWidget.template.html").then(function(templateHtml) { ctrl.template = templateHtml; transclude(scope, function(clone) { element.after(clone); }); }); } }; }); app.directive("inputWidget", function($compile) { return { priority: -400, require: "inputWidget", scope: { p1: "@", // variables used by the directive itself p2: "=?" // for example, to augment the template }, link: function(scope, element, attrs, ctrl, transclude) { var templateEl = angular.element(ctrl.template); element.after(templateEl); $compile(templateEl)(scope); templateEl.find("placeholder").replaceWith(element); } }; }); )有一个inputWidget.template.html元素,用于标记原始<placeholder>元素的放置位置:

<input>

Demo

(编辑)为什么2次编辑通过

上面的解决方案是一个“解决方法”,它避免了Angular中的错误,该错误是在注释元素上设置了插值,这是使用<div> <pre>p1: {{p1}}</pre> <div> <placeholder></placeholder> </div> <pre>p2: {{p2}}</pre> </div> 时剩下的内容。这在v1.4.0-beta.6中得到修复,通过修复,解决方案可以简化为:

transclude: element

Demo 2