【问题标题】:angularJS: How to call child scope function in parent scopeangularJS:如何在父范围内调用子范围函数
【发布时间】:2013-10-03 01:02:56
【问题描述】:

如何从父作用域调用子作用域中定义的方法?

function ParentCntl() {
    // I want to call the $scope.get here
}

function ChildCntl($scope) {
    $scope.get = function() {
        return "LOL";    
    }
}

http://jsfiddle.net/wUPdW/

【问题讨论】:

  • 最好的办法,定义一个服务,将该服务注入两个控制器。或者使用 rootscope。

标签: angularjs angularjs-scope


【解决方案1】:

您可以使用$broadcast从父母到孩子:

function ParentCntl($scope) {

    $scope.msg = "";
    $scope.get = function(){
        $scope.$broadcast ('someEvent');
        return  $scope.msg;        
    }
}

function ChildCntl($scope) {               
    $scope.$on('someEvent', function(e) {  
        $scope.$parent.msg = $scope.get();            
    });

    $scope.get = function(){
        return "LOL";    
    }
}

工作小提琴:http://jsfiddle.net/wUPdW/2/

更新:还有另一个版本,耦合度更低,可测试性更高:

function ParentCntl($scope) {
    $scope.msg = "";
    $scope.get = function(){
        $scope.$broadcast ('someEvent');
        return  $scope.msg;        
    }

    $scope.$on('pingBack', function(e,data) {  
        $scope.msg = data;        
    });
}

function ChildCntl($scope) {               
    $scope.$on('someEvent', function(e) {  
        $scope.$emit("pingBack", $scope.get());        
    });

    $scope.get = function(){
        return "LOL";    
    }
}

小提琴:http://jsfiddle.net/uypo360u/

【讨论】:

  • 太酷了!但是,如果您不(想)知道调用者范围在哪里(我的意思是在$scope.$parent$scope.$parent.$parent 等)怎么办?啊,是的:在参数中传递一个回调! :)
  • @user2173353 你说的很对;还有另一种方式:$emit 从孩子到父母。我认为是时候更新我的答案了..
  • 在这种情况下,调用全局监听器在哪里,子控制器是个好主意吗?不是反模式而且以后很难测试吗?我们不应该使用注射或smth吗?
  • @calmbird ,每一件事都必须小心使用,这是肯定的。有些人更喜欢在类似的情况下使用服务。无论如何,我添加了更优雅的版本(没有烦人的$parent
  • This approach 更干净。通过$broadcast 回调,您可以完全消除pingBack
【解决方案2】:

让我建议另一种解决方案:

var app = angular.module("myNoteApp", []);


app.controller("ParentCntl", function($scope) {
    $scope.obj = {};
});

app.controller("ChildCntl", function($scope) {
    $scope.obj.get = function() {
            return "LOL";    
    };
});

更少的代码和使用原型继承。

Plunk

【讨论】:

  • 有人能解释一下这种方法在哪些情况下比上面提到的事件驱动方法更好,如果是,为什么?如果您有多个 lvl 层次结构和子控制器怎么办?如果 obj.get 是在子控制器内的子控制器内定义的,只要所有控制器都没有定义相同的函数名称,这会起作用吗?提前谢谢你。
  • 让我纠正我所说的不完全正确的内容。您所说的正确:范围继承仅适用于一个方向....子->父。这里实际发生的是,如果您在子范围内定义 $scope.get,则“get”将仅在子范围内定义(有时称为原始定义)。但是当你定义 $scope.obj.get 时,子作用域会寻找在父作用域上定义的 obj,它在层次结构中。
  • 如果孩子有自己的隔离范围,这将如何工作?
  • 问题不是指隔离范围,但是如果您有隔离范围,则可以使用隔离范围绑定。哎呀,广播有点乱。
  • 如果您需要从父的控制器而不是模板访问子控制器的功能,我认为这个例子是不可能的。此示例仅适用于模板上的双向绑定,我假设它会一直轮询直到 $scope.obj.get() 是一个有效函数。
【解决方案3】:

在孩子初始化的时候,在父母上注册孩子的函数。为了清楚起见,我在模板中使用了“as”符号。

模板

<div ng-controller="ParentCntl as p">
  <div ng-controller="ChildCntl as c" ng-init="p.init(c.get)"></div>
</div>

控制器

...
function ParentCntl() {
  var p = this;
  p.init = function(fnToRegister) {
    p.childGet = fnToRegister;
  };
 // call p.childGet when you want
}

function ChildCntl() {
  var c = this;
  c.get = function() {
    return "LOL";    
  };
}

“但是”,你说,“ng-initisn't supposed to be used this way!”。嗯,是的,但是

  1. 该文档没有解释原因,并且
  2. 我不相信文档作者考虑了它的所有可能用例。

我说这是一个很好的用途。如果您想对我投反对票,请在评论中说明理由! :)

我喜欢这种方法,因为它使组件更加模块化。唯一的绑定在模板中,这意味着

  • 子控制器不必知道将其功能添加到哪个对象(如@canttouchit 的回答)
  • 父控件可以与任何其他具有获取功能的子控件一起使用
  • 不需要广播,除非您严格控制事件命名空间,否则在大型应用程序中广播会变得非常丑陋

这种方法更接近Tero's idea of modularising with directives(请注意,在他的模块化示例中,contestants 在模板中从父指令传递到“子”指令)。

确实,另一种解决方案可能是考虑将ChildCntl 实现为指令并使用&amp; 绑定来注册init 方法。

【讨论】:

  • 我知道这是一个旧帖子,但这似乎是个坏主意,因为在孩子被销毁后,父母可以保留对孩子的引用。
  • 这是一个比广播事件更干净的解决方案。不完美,但更好。虽然清理确实是个问题。
【解决方案4】:

您可以制作子对象。

var app = angular.module("myApp", []);


app.controller("ParentCntl", function($scope) {
    $scope.child= {};
    $scope.get = function(){
      return $scope.child.get(); // you can call it. it will return 'LOL'
    }
   // or  you can call it directly like $scope.child.get() once it loaded.
});

app.controller("ChildCntl", function($scope) {
    $scope.obj.get = function() {
            return "LOL";    
    };
});

这里的孩子正在证明get方法的目的地。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-14
    • 1970-01-01
    • 2014-01-26
    • 1970-01-01
    相关资源
    最近更新 更多