在ng-repeat中使用指令,以及作用域'@'的神秘力量

约拿:

如果您希望在工作代码中看到问题,请从此处开始:http : //jsbin.com/ayigub/2/edit

考虑以下几乎等效的方式来编写简单的指令:

app.directive("drinkShortcut", function() {
  return {
    scope: { flavor: '@'},
    template: '<div>{{flavor}}</div>'
  };
});

app.directive("drinkLonghand", function() {
  return {
    scope: {},
    template: '<div>{{flavor}}</div>',
    link: function(scope, element, attrs) {
      scope.flavor = attrs.flavor;
    }
  };
});

单独使用时,这两个指令的工作方式和行为相同:

  <!-- This works -->
  <div drink-shortcut flavor="blueberry"></div>
  <hr/>

  <!-- This works -->
  <div drink-longhand flavor="strawberry"></div>
  <hr/>

但是,在ng-repeat中使用时,仅快捷方式版本有效:

  <!-- Using the shortcut inside a repeat also works -->
  <div ng-repeat="flav in ['cherry', 'grape']">
    <div drink-shortcut flavor="{{flav}}"></div>
  </div>
  <hr/>

  <!-- HOWEVER: using the longhand inside a repeat DOESN'T WORK -->      
  <div ng-repeat="flav in ['cherry', 'grape']">
    <div drink-longhand flavor="{{flav}}"></div>
  </div>

我的问题是:

  1. 为什么长手版本在ng-repeat中不起作用?
  2. 您如何在ng-repeat中使用长手版本?
米歇尔·提里(Michelle Tilley):

在中drinkLonghand,您使用代码

scope.flavor = attrs.flavor;

在链接阶段,尚未评估插值属性,因此其值为undefined(他们的工作之外的ng-repeat,因为在这些情况下,您不使用字符串插值;你只是传递一个普通平凡的字符串,如“草莓”。)这是中提到的指令开发人员指南,有一个方法沿着Attributes名为的API文档中不存在$observe

使用$observe观察到,含有插(如属性值的变化src="{{bar}}")。这不仅非常有效,而且还是轻松获取实际值的唯一方法,因为在链接阶段尚未评估插值,因此此时将值设置为undefined

因此,要解决问题,您的drinkLonghand指令应如下所示:

app.directive("drinkLonghand", function() {
  return {
    template: '<div>{{flavor}}</div>',
    link: function(scope, element, attrs) {
      attrs.$observe('flavor', function(flavor) {
        scope.flavor = flavor;
      });
    }
  };
});

但是,这样做的问题是它没有使用隔离范围。因此,线

scope.flavor = flavor;

有可能覆盖名为的作用域上的预先存在的变量flavor添加空白隔离范围也不起作用;这是因为Angular尝试根据指令的作用域对字符串进行插值,在该作用域上没有调用属性flav(您可以通过scope.flav = 'test';在上方添加来测试attrs.$observe。)

当然,您可以使用隔离范围定义来解决此问题,例如

scope: { flav: '@flavor' }

或通过创建非隔离子范围

scope: true

或者不依赖于templatewith {{flavor}}而是直接进行一些DOM操作,例如

attrs.$observe('flavor', function(flavor) {
  element.text(flavor);
});

但这违反了练习的目的(例如,使用该drinkShortcut方法会更容易)。因此,为了使该指令起作用,我们将扩展$interpolate服务以在指令$parent范围内自行进行插值

app.directive("drinkLonghand", function($interpolate) {
  return {
    scope: {},
    template: '<div>{{flavor}}</div>',
    link: function(scope, element, attrs) {
      // element.attr('flavor') == '{{flav}}'
      // `flav` is defined on `scope.$parent` from the ng-repeat
      var fn = $interpolate(element.attr('flavor'));
      scope.flavor = fn(scope.$parent);
    }
  };
});

当然,这仅适用于的初始值scope.$parent.flav如果该值能够更改,则您必须使用$watch并重新评估插值函数的结果fn(我不是很想知道如何知道$watch;您可能只需要传递一个功能)。scope: { flavor: '@' }是避免必须管理所有这些复杂性的好捷径。

[更新]

要从评论中回答问题:

快捷方式如何在后台解决此问题?是像您一样使用$ interpolate服务,还是在做其他事情?

我对此不太确定,因此我查看了源代码。我在中找到以下内容compile.js

forEach(newIsolateScopeDirective.scope, function(definiton, scopeName) {
   var match = definiton.match(LOCAL_REGEXP) || [],
       attrName = match[2]|| scopeName,
       mode = match[1], // @, =, or &
       lastValue,
       parentGet, parentSet;

   switch (mode) {

     case '@': {
       attrs.$observe(attrName, function(value) {
         scope[scopeName] = value;
       });
       attrs.$$observers[attrName].$$scope = parentScope;
       break;
     }

因此,似乎attrs.$observe可以在内部告诉我们,使用与当前范围不同的范围作为属性观察的基础(最后一行的下一行,在上方break)。尽管可能自己想使用它,但请记住,任何带有双美元$$前缀的东西都应视为Angular私有API的私有内容,并且如有更改,恕不另行通知(更不用说您在使用@模式)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么ng-repeat指令创建子作用域?

在其他作用域对象的ng-repeat中使用另一个作用域对象值

无法在指令范本中使用ng-repeat

AngularJs在指令中使用ng-repeat给出类型错误

在$ scope。$ broadcast()/ $ scope。$ on()中使用angularjs ng-repeat指令

具有隔离作用域、ng-repeat 和 controllerAs 的 AngularJS 指令

在ng-repeat指令中进行角度选择:如何访问子作用域?

AngularJs,从嵌套ng-repeat内的指令访问父作用域

AngularJS:ng-repeat和作用域ng-click

ng-repeat,在指令内使用ng-click

在ng-repeat中使用时,ng-click在li上不起作用

在指令中使用ng-repeat导致表单验证无法正常工作

在ng-repeat指令中使用三元运算符

在自定义指令中使用ng Repeat来填充选择下拉列表

如何在嵌套的ng-repeat指令中使用控制语句(if语句)?

在 AngularJS 中的 ng-repeat 指令中使用自定义过滤器订购数据

如何在指令模板Angular JS中使用ng-repeat

指令在ng-repeat中不起作用

动态创建的AngularJS ng-repeat指令不起作用

如何使用ng-repeat中的数据调用作用域函数?

ng-repeat内的作用域未定义

无法更新ng-repeat假动画的作用域

AngularJS:在ng-repeat中爬上作用域树

无法显示ng-repeat子作用域属性

Angularjs - ng-repeat 和嵌套作用域

如何在ng-repeat中使用ng-if?

在“ng-repeat”中使用“ng-show”,

在ng-repeat中使用ng-model

ng-Click无法在ng-repeat中使用{{$ index}}