如何从Angular外部访问/更新$rootScope



我的应用程序初始化$rootScope中的对象图,如下。。。

var myApp = angular.module('myApp', []);
myApp.run(function ($rootScope) {
    $rootScope.myObject = { value: 1 };
});

然后消耗对象图中的数据(仅单向绑定(,如下所示。。。

<p>The value is: {{myObject.value}}</p>

这很好,但如果我随后(在页面渲染完成后(尝试更新$rootScope并用新对象替换原始对象,它将被忽略。我最初认为这是因为AngularJS保留了对原始对象的引用,尽管我已经替换了它

然而,如果我在控制器中包装使用HTML,我就能够以预期的方式重复更新其范围,并且修改会正确地反映在页面中。

myApp.controller('MyController', function ($scope, $timeout) {
    $scope.myObject = { value: 3 };
    $timeout(function() {
        $scope.myObject = { value: 4 };
        $timeout(function () {
            $scope.myObject = { value: 5 };
        }, 1000);
    }, 1000);
});

有没有任何方法可以通过$rootScope实现这一点,或者只能在控制器内完成?此外,是否有更推荐的模式来实施此类操作?具体来说,我需要一种方法来替换AngularJS在AngularJS代码之外使用的完整对象图。

提前感谢您的建议,Tim

编辑:正如评论中所建议的,我已经尝试在$apply中执行更改,但没有帮助:

setTimeout(function() {
    var injector = angular.injector(["ng", "myApp"]);
    var rootScope = injector.get("$rootScope");
    rootScope.$apply(function () {
        rootScope.myObject = { value: 6 };
    });
    console.log("rootScope updated");
}, 5000);

除了非常非常罕见的情况或调试目的外,这样做只是糟糕的实践(或表明应用程序设计糟糕(

对于非常非常罕见的情况(或调试(,您可以这样做:

  1. 访问您知道是应用程序一部分的元素,并将其包装为jqLite/jQuery元素
  2. 通过访问.scope().$root获取元素的Scope,然后获取$rootScope。(还有其他方法。(
  3. 做任何你做的事情,但把它包在$rootScope.$apply()中,这样Angular就会知道发生了什么,并发挥它的魔力

例如:

function badPractice() {
  var $body = angular.element(document.body);  // 1
  var $rootScope = $body.scope().$root;        // 2
  $rootScope.$apply(function () {              // 3
    $rootScope.someText = 'This is BAD practice :(';
  });
}

另请参阅简短演示


编辑

Angular 1.3.x引入了一个选项,禁止调试信息附加到DOM元素(包括scope(:$compileProvider.debuginInfoEnabled((
建议在生产中禁用调试信息(为了性能(,这意味着上述方法将不再工作。

如果您只想调试一个实时(生产(实例,您可以调用angular.reloadWithDebugInfo((,它将在启用调试信息的情况下重新加载页面

或者,您可以使用Plan B(通过元素的注入器访问$rootScope(:

function badPracticePlanB() {
  var $body = angular.element(document.body);           // 1
  var $rootScope = $body.injector().get('$rootScope');  // 2b
  $rootScope.$apply(function () {                       // 3
    $rootScope.someText = 'This is BAD practice too :(';
  });
}

更新$rootScope后,调用$rootScope$apply((来更新绑定。

将修改作用域视为一个原子操作,$apply((提交这些更改。

如果要更新根作用域的对象,请将$rootScope注入控制器:

myApp.controller('MyController', function ($scope, $timeout, $rootScope) {
    $rootScope.myObject = { value: 3 };
    $timeout(function() {
        $rootScope.myObject = { value: 4 };
        $timeout(function () {
            $rootScope.myObject = { value: 5 };
        }, 1000);
    }, 1000);
});

演示小提琴

最新更新