如何从 AngularJS 中的自定义指令 * 具有自己的范围 * 中访问父范围? [英] How to access parent scope from within a custom directive *with own scope* in AngularJS?

查看:23
本文介绍了如何从 AngularJS 中的自定义指令 * 具有自己的范围 * 中访问父范围?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找在指令中访问父"范围的任何方式.作用域、嵌入、要求、从上面传入变量(或作用域本身)等的任何组合.我完全愿意向后弯腰,但我想避免一些完全hacky 或无法维护的东西.例如,我知道我现在可以通过从 preLink 参数中获取 $scope 并遍历它的 $sibling 范围来找到概念上的父"来做到这一点.

我真正想要的是能够在父作用域中$watch 一个表达式.如果我能做到这一点,那么我就可以在这里完成我想要做的事情:AngularJS - 如何使用变量渲染部分?>

一个重要的注意事项是指令必须在同一个父作用域内重复使用.因此默认行为(范围:false)对我不起作用.我需要每个指令实例都有一个单独的作用域,然后我需要 $watch 一个位于父作用域中的变量.

一个代码示例值 1000 字,所以:

app.directive('watchingMyParentScope', function() {返回 {要求:/* ?*/,范围:/* ?*/,转置:/* ?*/,控制器:/* ?*/,编译:函数(el,attr,trans){//我可以以某种方式从嵌入函数中获取 $parent 吗?返回 {前:函数($s,$e,$a,parentControl){//我可以从父控制器获取 $parent 吗?//通过在该控制器中设置 this.$scope = $scope ?//我可以从当前的 $scope 中获取 $parent 吗?//我可以将 $parent 范围作为属性传入并定义//它是该指令范围定义的一部分吗?//我不明白指令是如何工作的//他们的范围如何与他们的父级相关?},帖子:函数($s,$e,$a,parentControl){//调用 postLink 时我的情况是否有所改善?}}}};});

解决方案

参见 AngularJS 中范围原型/原型继承的细微差别是什么?

总结:指令访问其父($parent)作用域的方式取决于指令创建的作用域类型:

  1. default (scope: false) - 该指令不会创建新的作用域,因此这里没有继承.指令的范围与父/容器的范围相同.在链接函数中,使用第一个参数(通常是 scope).

  2. scope: true - 该指令创建一个新的子作用域,该子作用域原型继承自父作用域.在父作用域上定义的属性可用于指令 scope(因为原型继承).请注意写入原始范围属性 - 这将在指令范围上创建一个新属性(隐藏/隐藏同名的父范围属性).

  3. scope: { ... } - 该指令创建一个新的隔离/隔离作用域.它不典型地继承父作用域.您仍然可以使用 $parent 访问父作用域,但通常不建议这样做.相反,您应该使用 =, @ 通过使用指令的同一元素上的附加属性指定指令需要的父作用域属性(和/或函数), 和 & 符号.

  4. transclude: true - 该指令创建一个新的transcluded"子作用域,典型地从父作用域继承.如果该指令还创建了一个隔离作用域,则嵌入的和隔离的作用域是同级的.每个作用域的 $parent 属性引用相同的父作用域.
    Angular v1.3 更新:如果指令还创建了一个隔离作用域,则嵌入的作用域现在是隔离范围的子级.嵌入的和隔离的作用域不再是兄弟作用域.嵌入作用域的 $parent 属性现在引用了隔离作用域.

上面的链接有四种类型的例子和图片.

您无法访问指令的编译函数中的范围(如此处所述:https://github.com/angular/angular.js/wiki/Dev-Guide:-Understanding-Directives).您可以在链接函数中访问指令的作用域.

观看:

对于上面的 1. 和 2.:通常你通过一个属性指定指令需要哪个父属性,然后 $watch it:

scope.$watch(attrs.attr1, function() { ... });

如果您正在查看对象属性,则需要使用 $parse:

var model = $parse(attrs.attr2);scope.$watch(model, function() { ... });

对于上面的 3.(隔离作用域),注意使用 @= 符号为指令属性指定的名称:

范围:{localName3: '@attr3',attr4: '='//此处,使用与属性相同的名称},链接:函数(范围,元素,属性){scope.$watch('localName3', function() { ... });scope.$watch('attr4', function() { ... });

I'm looking for any manner of accessing the "parent" scope within a directive. Any combination of scope, transclude, require, passing in variables (or the scope itself) from above, etc. I'm totally willing to bend over backwards, but I want to avoid something totally hacky or unmaintainable. For example, I know I could do it right now by taking the $scope from the preLink parameters and iterating over it's $sibling scopes to find the conceptual "parent".

What I really want is to be able to $watch an expression in the parent scope. If I can do that, then I can accomplish what I'm trying to do over here: AngularJS - How to render a partial with variables?

An important note is that the directive must be re-usable within the same parent scope. Therefore the default behavior (scope: false) doesn't work for me. I need an individual scope per instance of the directive, and then I need to $watch a variable that lives in the parent scope.

A code sample is worth 1000 words, so:

app.directive('watchingMyParentScope', function() {
    return {
        require: /* ? */,
        scope: /* ? */,
        transclude: /* ? */,
        controller: /* ? */,
        compile: function(el,attr,trans) {
            // Can I get the $parent from the transclusion function somehow?
            return {
                pre: function($s, $e, $a, parentControl) {
                    // Can I get the $parent from the parent controller?
                    // By setting this.$scope = $scope from within that controller?

                    // Can I get the $parent from the current $scope?

                    // Can I pass the $parent scope in as an attribute and define
                    // it as part of this directive's scope definition?

                    // What don't I understand about how directives work and
                    // how their scope is related to their parent?
                },
                post: function($s, $e, $a, parentControl) {
                    // Has my situation improved by the time the postLink is called?
                }
            }
        }
    };
});

解决方案

See What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

To summarize: the way a directive accesses its parent ($parent) scope depends on the type of scope the directive creates:

  1. default (scope: false) - the directive does not create a new scope, so there is no inheritance here. The directive's scope is the same scope as the parent/container. In the link function, use the first parameter (typically scope).

  2. scope: true - the directive creates a new child scope that prototypically inherits from the parent scope. Properties that are defined on the parent scope are available to the directive scope (because of prototypal inheritance). Just beware of writing to a primitive scope property -- that will create a new property on the directive scope (that hides/shadows the parent scope property of the same name).

  3. scope: { ... } - the directive creates a new isolate/isolated scope. It does not prototypically inherit the parent scope. You can still access the parent scope using $parent, but this is not normally recommended. Instead, you should specify which parent scope properties (and/or function) the directive needs via additional attributes on the same element where the directive is used, using the =, @, and & notation.

  4. transclude: true - the directive creates a new "transcluded" child scope, which prototypically inherits from the parent scope. If the directive also creates an isolate scope, the transcluded and the isolate scopes are siblings. The $parent property of each scope references the same parent scope.
    Angular v1.3 update: If the directive also creates an isolate scope, the transcluded scope is now a child of the isolate scope. The transcluded and isolate scopes are no longer siblings. The $parent property of the transcluded scope now references the isolate scope.

The above link has examples and pictures of all 4 types.

You cannot access the scope in the directive's compile function (as mentioned here: https://github.com/angular/angular.js/wiki/Dev-Guide:-Understanding-Directives). You can access the directive's scope in the link function.

Watching:

For 1. and 2. above: normally you specify which parent property the directive needs via an attribute, then $watch it:

<div my-dir attr1="prop1"></div>

scope.$watch(attrs.attr1, function() { ... });

If you are watching an object property, you'll need to use $parse:

<div my-dir attr2="obj.prop2"></div>

var model = $parse(attrs.attr2);
scope.$watch(model, function() { ... });

For 3. above (isolate scope), watch the name you give the directive property using the @ or = notation:

<div my-dir attr3="{{prop3}}" attr4="obj.prop4"></div>

scope: {
  localName3: '@attr3',
  attr4:      '='  // here, using the same name as the attribute
},
link: function(scope, element, attrs) {
   scope.$watch('localName3', function() { ... });
   scope.$watch('attr4',      function() { ... });

这篇关于如何从 AngularJS 中的自定义指令 * 具有自己的范围 * 中访问父范围?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆