web-dev-qa-db-ja.com

外部から$ rootScopeにアクセス/更新する方法Angular

私のアプリケーションは、このように$ 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によって消費される完全なオブジェクトグラフを置き換える方法が必要です。

事前に、ご提案をありがとう、ティム

編集:コメントで示唆されているように、$ 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);
38
Tim Coulter

非常にまれなケースやデバッグ目的を除いて、これを行うのはただの悪い習慣です(または悪いアプリケーション設計の指標です!)

非常にまれなケース(またはデバッグ)の場合、次のように実行できます。

  1. アプリの一部であることがわかっている要素にアクセスし、jqLit​​e/jQuery要素としてラップします。
  2. .scope().$rootにアクセスして、要素のスコープを取得してから_$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 :(';
  });
}
_

こちらもご覧ください短いデモ


[〜#〜] edit [〜#〜]

Angular 1.3.xは、デバッグ情報がDOM要素(scopeを含む)に添付されないようにするオプションを導入しました:$ compileProvider.debugInfoEnabled() =
本番環境ではdebug-infoを無効にすることをお勧めします(パフォーマンスのため)。つまり、上記の方法はもう機能しません。

ライブ(プロダクション)インスタンスをデバッグするだけの場合、angular.reloadWithDebugInfo()を呼び出すことができます。ページwithdebug-infoが有効になっています。

または、プラン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 :(';
  });
}
_
86
gkalpak

$ rootScopeを更新したら、$ rootScope。$ apply()を呼び出してバインディングを更新します。

スコープの変更をアトミック操作と考え、$ apply()はそれらの変更をコミットします。

1
Martin