43

私のアプリケーションは、このように $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);
4

3 に答える 3

94

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

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

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

この短いデモも参照してください。


編集

Angular 1.3.x では、debug-info が DOM 要素 (を含む) にアタッチされないようにするオプションが導入されましたscope: $compileProvider.debugInfoEnabled(
)メソッドはもう機能しません。

ライブ (本番) インスタンスをデバッグするだけの場合は、angular.reloadWithDebugInfo()を呼び出すことができます。これにより、デバッグ情報が有効になっているページがリロードされます。

$rootScope別の方法として、プラン B (要素のインジェクターを介してアクセスする) を使用することもできます。

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 :(';
  });
}
于 2014-07-06T13:20:29.197 に答える
1

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

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

于 2014-07-06T12:57:22.880 に答える
-2

ルート スコープのオブジェクトを更新する場合は$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);
});

デモフィドル

于 2014-07-06T11:48:34.580 に答える