当前位置: 首页 > 面试题库 >

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

从建明
2023-03-14
问题内容

如果您希望在工作代码中看到问题,请从此处开始: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中使用长手版本?

问题答案:

在中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服务,还是在做其他事情?

我对此不太确定,因此我查看了源html" target="_blank">代码。我在中找到以下内容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的私有内容,并且如有更改,恕不另行通知(更不用说您在使用@模式)。



 类似资料:
  • 因此,我希望可以使用优先级来确保我的指令首先运行,并最终创建一个隔离范围,当运行时,它重用隔离范围,而不是创建一个原型上从父范围继承的范围。文档声明该指令在优先级下运行。尚不清楚是高优先级还是低优先级。当我在指令中使用优先级时,没有什么不同,所以我尝试了。但这使情况变得更糟:我的双向绑定变成,并且我的指令不显示任何内容。 我创造了一个小提琴来显示我的问题。我已经注释掉了指令中的设置。我有一个nam

  • 问题内容: 我花了一段时间试图找到一个优雅的解决方案,而我却找到了一个“可行”的解决方案,它感觉不是最简单或正确的做事方式。 所以,我的问题是…如何动态加载指令!在某些情况下,以下是我希望我能摆脱它的方式!除了模板加载之外,我没有包含路由或其他任何内容,而是为下面的控制器分配了ng- controller。 app.js template.html 任何人都可以提供的建议将不胜感激,如果我做任何明

  • Angularjs ng用div标记重复。。我有一个带有div标记的代码,如图所示。。我想重复整个div,在第二个循环中img src是不同的。。如何使用angularjs中的ng repeat指令执行此操作?

  • 问题内容: 我有一张桌子,其中的行通过重复。我正在尝试创建一个模板,为每一行生成列 问题是我的自定义td模板根本没有呈现。在这里,我打算用n个s 代替- 这将根据我的数据对象上的属性数量来确定,但是目前,我只是试图获得一个简单的指令,该指令将输出两列。 MYPLUNKER:显示此问题的一个实例和指令代码。 问题答案: 如注释中所指出,指令模板应具有单个根元素。因此,我建议您将元素移动到指令的模板,

  • 本文向大家介绍AngularJS ng-repeat指令及Ajax的应用实例分析,包括了AngularJS ng-repeat指令及Ajax的应用实例分析的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了AngularJS ng-repeat指令及Ajax的应用。分享给大家供大家参考,具体如下: ng-repeat 指令用于循环输出指定次数的 HTML 元素。集合必须是数组或对象。 定义:

  • 问题内容: 我正在开发一个页面,我需要在其中显示一些框(使用),其中包含频道信息以及显示位置(城市)。 我面临的问题是当我重复第二遍时: 这应该获得第一个ng-repeat的$ index值,并使用显示频道的位置创建一个新数组。它确实做到了。但是,当我使用此数组应用第二个ng- repeat时,它无法正常工作。 说我的html看起来像这样(PS:我需要使用索引值而不是因为我将这些框放到列中) JS