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

Tim*_*ter 38 angularjs rootscope

我的应用程序初始化$ rootScope中的对象图,就像这样......

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

myApp.run(function ($rootScope) {
    $rootScope.myObject = { value: 1 };
});
Run Code Online (Sandbox Code Playgroud)

...然后从该对象图中消耗数据(仅限单向绑定),就像这样......

<p>The value is: {{myObject.value}}</p>
Run Code Online (Sandbox Code Playgroud)

这工作正常,但如果我随后(在页面渲染完成后)尝试更新$ 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);
});
Run Code Online (Sandbox Code Playgroud)

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

蒂姆,提前谢谢你的建议

编辑:正如评论中所建议的,我已经尝试在$ 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);
Run Code Online (Sandbox Code Playgroud)

gka*_*pak 88

除了非常非常罕见的情况或调试目的,这样做只是BAD练习(或BAD应用程序设计的指示)!

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

  1. 访问您知道属于应用程序的元素并将其包装为jqLit​​e/jQuery元素.
  2. 获取元素的Scope,然后$rootScope访问.scope().$root.(还有其他方法.)
  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 :(';
  });
}
Run Code Online (Sandbox Code Playgroud)

另见这个简短的演示.


编辑

Angular 1.3.x引入了一个禁用debug-info附加到DOM元素(包括scope)的选项:$ compileProvider.debugInfoEnabled()
建议在生产中禁用debug-info(为了性能),这意味着上面的方法不再适用.

如果您只想调试实时(生产)实例,可以调用angular.reloadWithDebugInfo(),它将重新加载启用 debug-info 的页面.

或者,您可以使用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 :(';
  });
}
Run Code Online (Sandbox Code Playgroud)

  • 如果你能解释*为什么*这是一个不好的做法并且展示出正确的做法,那么这个答案对于OP以外的其他人来说会更有用.:) (6认同)