web-dev-qa-db-fra.com

Comment accéder / mettre à jour $ rootScope de l’extérieur Angular

Mon application initialise un graphe d'objet dans $ rootScope, comme ceci ...

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

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

... et consomme ensuite les données de ce graphe d'objets (liaison unidirectionnelle uniquement), comme ceci ...

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

Cela fonctionne bien, mais si par la suite (une fois le rendu de la page terminé), j'essaie de mettre à jour le $ rootScope et de remplacer l'objet d'origine par un nouvel objet, celui-ci est ignoré. J'ai initialement supposé que c'était parce qu'AngularJS conservait une référence à l'objet d'origine, même si je l'avais remplacé.

Toutefois, si j'emballe le code HTML consommateur dans un contrôleur, je suis en mesure de mettre à jour son étendue de la manière prévue et les modifications sont correctement reflétées dans la 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);
});

Existe-t-il un moyen d'accomplir cela via le $ rootScope, ou peut-on uniquement le faire à l'intérieur d'un contrôleur? En outre, existe-t-il un modèle plus recommandé pour la mise en œuvre de telles opérations? Plus précisément, j'ai besoin d'un moyen de remplacer les graphiques d'objet complets consommés par AngularJS en dehors du code AngularJS.

Merci d’avance pour vos suggestions, Tim

Edit: Comme suggéré dans les commentaires, j’ai essayé d’exécuter la modification dans $ apply, mais cela n’aide en rien:

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

Sauf pour de très rares cas ou à des fins de débogage, cette opération n'est que mauvaise pratique (ou une indication de la conception d'une mauvaise application)!

Dans les cas très rares (ou de débogage), vous pouvez le faire comme ceci:

  1. Accédez à un élément dont vous savez qu'il fait partie de l'application et enveloppez-le en tant qu'élément jqLite/jQuery.
  2. Obtenez la portée de l'élément, puis le $rootScope En accédant à .scope().$root. (Il y a aussi d'autres moyens.)
  3. Faites ce que vous faites, mais enveloppez-le dans $rootScope.$apply(), donc Angular) saura que quelque chose se passe et fera sa magie.

Par exemple.:

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

Voir aussi ceci brève démonstration.


[~ # ~] éditer [~ # ~]

Angular 1.3.x a introduit une option pour désactiver l’attachement de debug-info aux éléments DOM (y compris le scope): $ compileProvider.debugInfoEnabled () =
Il est conseillé de désactiver les informations de débogage en production (pour des raisons de performances), ce qui signifie que la méthode ci-dessus ne fonctionnerait plus.

Si vous voulez juste déboguer une instance en direct (production), vous pouvez appeler angular.reloadWithDebugInfo (), ce qui rechargera la page avec debug-info activé.

Alternativement, vous pouvez utiliser Plan B (accès au $rootScope Via l'injecteur d'un élément):

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

Après avoir mis à jour l'appel $ rootScope, appelez $ rootScope. $ Apply () pour mettre à jour les liaisons.

Pensez à modifier les portées comme une opération atomique et $ apply () valide ces modifications.

1
Martin