【问题标题】:AngularJS controller inheritanceAngularJS 控制器继承
【发布时间】:2013-03-01 10:28:27
【问题描述】:

AngularJS 有一个基于 DOM 的控制器继承,如 Angular 文档中所述。

<div ng-controller="BaseController">
    <p>Base Controller Value: {{value}}</p>
    <button ng-click="updateValue()">Update In Base</button>
    <div ng-controller="DerivedController">
        <p>Derived Controller Value: {{value}}</p>
        <button ng-click="updateValue()">Update In Derived</button>
    </div>
</div>

范围变量“value”仅存在于 BaseController 中。基于此,在更改 BaseController 或 DerivedController 中的方法的值时,我希望这两个值都需要更新。但只有单个作用域变量得到更新。

这是一个演示相同示例的小提琴:http://jsfiddle.net/6df6S/1/

如何在一个级别进行更改以传播到当前范围的直接子级和直接父级。

我们可以通过使用

来实现

$scope.$watch

有没有办法在不使用它或任何此类观察者的情况下做到这一点?

编辑 1:

这里使用 $scope.$watch 就是我的意思

$scope.$watch("value", function () {
   $scope.$broadcast("childChangeListener"); //Downwards to all children scopes
   $scope.$emit("parentChangeListener"); //Upwards to all parent scopes
});

我一直在寻找在不使用这种机制的情况下在所有范围内更新值的方法。

【问题讨论】:

  • 请使用$rootScope
  • 有没有办法共享$scope而不用把属性和方法放到$rootScope中?
  • 请不要使用 $rootScope。改用服务在控制器之间共享数据(请参阅我的回答)。
  • 有什么特别的理由选择服务而不是$rootscope
  • @AdityaPonkshe,使用$rootScope 类似于全局变量,即usually bad

标签: angularjs angularjs-scope


【解决方案1】:

看看$broadcast 方法。引用文档:

将事件名称向下调度到所有子范围(及其 children) 通知已注册的 ng.$ro​​otScope.Scope#$on 监听器。

【讨论】:

  • 谢谢布鲁诺。但我一直在寻找其他东西,因为观察“值”会触发每个动作,甚至与这个“值”无关,以检查“值”是否发生了变化,因为作为每个摘要周期的一部分,都会验证观察变量。
  • 有什么特别的理由选择服务而不是$rootscope
【解决方案2】:

您不能直接引用子控制器中的字符串值。由于原型继承设置属性 value 在子作用域(当您使用子控制器时创建)在子作用域上创建该属性,而不是更新父作用域属性。

您的范围不是模型,因此我们应该避免使用大量属性污染$scope 变量。创建一个模型对象并在其上创建子属性。然后可以将此对象沿子控制器\范围传递。

我修改了你的jsfiddle来解释上述观点。

另外我强烈建议你阅读这个wiki page,了解原型继承的麻烦。

【讨论】:

  • +1,但我建议使用服务在控制器之间共享数据,而不是依赖某种 HTML 结构来提供范围继承(请参阅我的回答)。
【解决方案3】:

当多个控制器需要访问相同的数据时,应使用service。您不应该依赖范围继承,因为它限制了您编写 HTML 的方式。例如,将来您决定 DerivedController 不应该是 BaseController 的子级。

您的服务通常应提供公共 API,并隐藏实现。这使得重构内部更容易。

HTML:

<div ng-controller="BaseController">
    <p>Base Controller Value: {{model.getValue()}}</p>
    <button ng-click="model.updateValue('Value updated from Base')">Update In Base</button>
    <div ng-controller="DerivedController">
        <p>Derived Controller Value: {{model.getValue()}}</p>
        <button ng-click="model.updateValue('Value updated from Derived')">Update In Derived</button>
    </div>
</div>

JavaScript:

app.factory('sharedModel', function () {
    // private stuff
    var model = {
        value: "initial Value"
    };
    // public API
    return {
        getValue:    function() { 
           return model.value; 
        },
        updateValue: function(value) {
           model.value = value;
        }
    };
});

function BaseController($scope, sharedModel) {
    $scope.model = sharedModel;
}

function DerivedController($scope, sharedModel) {
    $scope.model = sharedModel;
}

Fiddle.

另外,我不建议使用 $rootScope 在控制器之间共享。

【讨论】:

  • 我明白你的意思,但这种方法似乎很冗长。不使用update方法,我们可以不更新service返回的模型吗?
  • 只是说你救了我:)
  • @Chandermani:我同意,我认为在这里使用服务是不雅的。看看这个答案,以一种不依赖于 HTML 结构的方式进行控制器继承:stackoverflow.com/a/20230720/62571
  • 服务 404 的第一个链接。我认为这是更新后的 URL:docs.angularjs.org/guide/services
  • @Chandermani,我更新了答案(2 年后,嗯,迟到总比没有好??)解释冗长——即方法的使用——对于封装服务。
【解决方案4】:

您的小提琴中的绑定直接在范围内的属性上。您需要的继承可以通过对范围内的对象进行数据绑定来实现。

http://jsfiddle.net/2Dtyq/

scope.shared = {}    
scope.shared.value = "Something"

不仅仅是

scope.value= "Something"

发生了什么?
在构造 DerivedController 时,传入的作用域在原型上继承自 BaseController 的作用域。
DerivedController 的作用域对象仍然没有自己的称为“值”的属性。因此它仍然绑定到它从父级范围获得的属性。
现在,如果您单击 Update In Base 按钮,它将反映在两个绑定中。 当你点击Update In Derived按钮时,一个名为“value”的新属性会在DerviedController的作用域上创建。因此,与父级的 value 属性的绑定被破坏。再点击 Update In Base 不会刷新第二个数据绑定。
将其放在单独的对象中可防止创建新属性,因此仍保持继承。

【讨论】:

  • 这个和@Chandermani 的答案是正确的答案。此处介绍的其他解决方案是变通方法,但不能确定行为的根本原因。
【解决方案5】:

使用对象而不是使用原始值。在你的情况下定义一个这样的对象

$scope.obj = {"value":"base"}; 

并尝试(obj.value)。它会起作用的。

【讨论】:

  • 你的意思是 $scope.obj = {"value":"base"};因为你的对我来说似乎不是有效的 JS。
【解决方案6】:

这是因为 ngController 创建了一个新的 $scope 并且 value 的引用不一样。 你可以使用$parent 属性来解决这个问题:

<div ng-controller="BaseController">
    <p>Base Controller Value: {{value}}</p>
    <div ng-controller="DerivedController">
        <p>Derived Controller Value: {{$parent.value}}</p>
    </div>
</div>

在 DerivedController 中你可以使用类似的东西:$scope.$parent.value

但最好的实现方式是使用controllerAs 语法。

<div ng-controller="BaseController as BaseController ">
<p>Base Controller Value: {{BaseController.value}}</p>
<div ng-controller="DerivedController">
    <p>Derived Controller Value: {{BaseController.value}}</p>
</div>

在 DerivedController 中你可以使用类似的东西:$scope.BaseController.value

这使代码更具可读性,因为您知道所引用的控制器是什么。 更多信息请关注 ngController DocsDigging into Angular’s “Controller as” syntax by ToddMotto

【讨论】:

    猜你喜欢
    • 2018-01-27
    • 2020-06-24
    • 1970-01-01
    • 2015-07-14
    • 1970-01-01
    • 2014-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多