如何从 Angular 外部访问/更新 $rootScope [英] How to access/update $rootScope from outside Angular

查看:28
本文介绍了如何从 Angular 外部访问/更新 $rootScope的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My application initializes an object graph in $rootScope, like this ...

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

myApp.run(function ($rootScope) {
    $rootScope.myObject = { value: 1 };
});

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

... and then consumes data from that object graph (1-way binding only), like this ...

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

这工作正常,但如果我随后(在页面渲染完成后)尝试更新 $rootScope 并用新对象替换原始对象,它将被忽略.我最初认为这是因为 AngularJS 保留了对原始对象的引用,即使我已经替换了它.

This works fine, but if I subsequently (after page rendering has completed) try to update the $rootScope and replace the original object with a new one, it is ignored. I initially assumed that this was because AngularJS keeps a reference to the original object, even though I have replaced it.

但是,如果我将消费 HTML 包装在控制器中,我能够以预期的方式重复更新其范围,并且修改会正确反映在页面中.

However, if I wrap the the consuming HTML in a controller, I am able to repeatedly update its scope in the intended manner and the modifications are correctly reflected in the page.

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 使用的完整对象图.

Is there any way to accomplish this via the $rootScope, or can it only be done inside a controller? Also, is there a more recommended pattern for implementing such operations? Specifically, I need a way to replace complete object graphs that are consumed by AngularJS from outside of AngularJS code.

提前感谢您的建议,提姆

Thanks, in advance, for your suggestions, Tim

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

As suggested in comments, I have tried executing the change inside $apply, but it doesn't help:

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);

推荐答案

除了非常非常罕见的情况或调试目的,这样做只是不好的做法(或不好的应用程序设计的迹象)!

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

For the very, very rare cases (or debugging), you can do it like this:

  1. 访问您知道是应用程序一部分的元素,并将其包装为 jqLit​​e/jQuery 元素.
  2. 通过访问 .scope().$root 获取元素的 Scope,然后获取 $rootScope.(还有其他方法.)
  3. 做任何你想做的事,但把它包装在 $rootScope.$apply() 中,这样 Angular 就会知道发生了什么并发挥它的魔力.
  1. Access an element that you know is part of the app and wrap it as a jqLite/jQuery element.
  2. Get the element's Scope and then the $rootScope by accessing .scope().$root. (There are other ways as well.)
  3. Do whatever you do, but wrap it in $rootScope.$apply(), so Angular will know something is going on and do its magic.

例如:

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.debugInfoEnabled()
建议在生产中禁用 debug-info(为了性能),这意味着上述方法将不再适用.

Angular 1.3.x introduced an option to disable debug-info from being attached to DOM elements (including the scope): $compileProvider.debugInfoEnabled()
It is advisable to disable debug-info in production (for performance's sake), which means that the above method would not work any more.

如果您只想调试实时(生产)实例,可以调用 angular.reloadWithDebugInfo(),这将重新加载页面 启用调试信息.

If you just want to debug a live (production) instance, you can call angular.reloadWithDebugInfo(), which will reload the page with debug-info enabled.

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

Alternatively, you can go with Plan B (accessing the $rootScope through an element's injector):

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 :(';
  });
}

这篇关于如何从 Angular 外部访问/更新 $rootScope的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆