在Angular中,这是不好的做法

时间:2013-10-16 12:38:17

标签: angularjs angularjs-directive angularjs-scope

我正在制作一个自定义指令,并试图让它独立于jQuery。为了在没有jQuery的情况下实现这一点,Scopes(父级和子级)可能必须直接交互。我当然希望尽可能避免“不良做法”,所以我的问题是:

让子范围直接调用父范围的函数是不好的做法吗?如果是这样,无论如何都要获得管理范围的控制器或元素?

这是必要的原因是指令可能有多个嵌套范围。我需要访问一个非常特殊的一个,它不一定是当前范围的直接父级(尽管它是一个祖先)。

编辑:UseCase Elaboration

该模块包含两个指令。其中任何一个都可以嵌套在任意数量的父指令中。这个子指令确实需要相应的父指令,但是在嵌套父类的情况下,它只获得最直接父节点的控制器。

正常使用它通常是:

<element parent-attr-dir="val">
    <element child-attr-dir="val"></element>
</element>

请注意,属性的值必须匹配。这就决定了附加哪个“祖先”。

高级用法可能类似于:

<element parent-attr-dir="value1">
    <element parent-attr-dir="value2">
        <element child-attr-dir="value1">Will run on top most ancestor</element>
        <element child-attr-dir="value2">Will run on immediate parent</element>
    </element>
    <element parent-attr-dir="value3">
        <element child-attr-dir="value3">Will run on immediate parent</element>
        <element child-attr-dir="value1">Will run on top most ancestor</element>
    </element>
    <element child-attr-dir="val">Will not run!!</element>
</element>

编辑:问题解决方案

这有效,但需要知道它是否不好。

var _p = scope;
while (_p !== null) {
    if (_p.doSomething 
    &&  /* some other criteria. */ ) {
        _p.doSomething(scope);
    }
    _p = _p.$parent;
}

编辑:使用jQuery解决方案

这有效,但需要jQuery,因为jQLite没有父(选择器),只有parent()。

$(element).parents('[attrname=value]').controller('moduleName').funcName()

1 个答案:

答案 0 :(得分:1)

一个解决方案是让孩子们需要父指令,而父母可以选择要求父指令。然后一个孩子调用其直接父控制器的方法,传递标准值;如果父控制器不符合条件,它会将调用转发给自己的父(如果有的话),或者没有任何反应。解决方案草图:

app.directive("parentAttrDir", function() {
    return {
        require: ["?^parentAttrDir","parentAttrDir"],
        link: function(scope,elem,attrs,controllers) {
            var parentAttrDir = controllers[0],
                thisController = controllers[1],
                criterion = attrs.parentAttrDir;
            thisController.parent = parentAttrDir;
            thisController.criterion = criterion;
        },
        controller: function($scope) {
            this.doSomething = function(data,criterion) {
                if( this.criterion === criterion ) {
                    // actually do something with the data
                }
                else if( this.parent != null ) {
                    return this.parent.doSomething(data,criterion);
                }
            };
        }
    };
});

app.directive("childAttrDir", function() {
    return {
        require: "^parentAttrDir",
        link: function(scope,elem,attrs,parentAttrDir) {
            var criterion = attrs.childAttrDir;
            // EXAMPLE USAGE FROM CHILD
            scope.doSomeAction = function(data) {
                parentAttrDir.doSomething(data,criterion);
            };
        }
    };
});