Quel est le cycle de vie d'un contrôleur AngularJS?

199

Quelqu'un peut-il clarifier le cycle de vie d'un contrôleur AngularJS?

  • Un contrôleur est-il un singleton, ou créé / détruit à la demande?
  • Dans ce dernier cas, qu'est-ce qui déclenche la création / destruction du contrôleur?

Prenons l'exemple ci-dessous:

var demoApp = angular.module('demo')
  .config(function($routeProvider, $locationProvider) {
    $routeProvider
      .when('/home', {templateUrl: '/home.html', controller: 'HomeCtrl'})
      .when('/users',{templateUrl: '/users.html', controller: 'UsersCtrl'})
      .when('/users/:userId', {templateUrl: '/userEditor.html', controller: 'UserEditorCtrl'});
  });

demoApp.controller('UserEditorCtrl', function($scope, $routeParams, UserResource) {
  $scope.user = UserResource.get({id: $routeParams.userId});
});

par exemple:

Dans l'exemple ci-dessus, lorsque je navigue vers /users/1, l'utilisateur 1 est chargé et défini sur $scope.

Ensuite, lorsque je navigue vers /users/2, l'utilisateur 2 est chargé. La même instance est-elle UserEditorCtrlréutilisée ou une nouvelle instance est-elle créée?

  • S'il s'agit d'une nouvelle instance, qu'est-ce qui déclenche la destruction de la première instance?
  • S'il est réutilisé, comment ça marche? (c'est-à-dire que la méthode de chargement des données semble s'exécuter lors de la création du contrôleur)
Marty Pitt
la source

Réponses:

227

Eh bien, en fait, la question est de savoir quel est le cycle de vie d'un ngViewcontrôleur.

Les contrôleurs ne sont pas des singletons. N'importe qui peut créer un nouveau contrôleur et ils ne sont jamais détruits automatiquement. Le fait est qu'il est généralement lié au cycle de vie de sa portée sous-jacente. Le contrôleur n'est pas automatiquement détruit chaque fois que sa portée est détruite. Cependant, après avoir détruit une portée sous-jacente, son contrôleur est inutile (au moins, par conception, il devrait l'être).

Pour répondre à votre question spécifique, une ngViewdirective (ainsi que pour une ngControllerdirective) créera toujours un nouveau contrôleur et une nouvelle portée à chaque fois qu'une navigation se produit. Et la dernière portée va également être détruite .

Les "événements" du cycle de vie sont assez simples. Votre "événement de création" est la construction de votre contrôleur lui-même. Exécutez simplement votre code. Pour savoir quand cela devient inutile ( "événement de destruction" ), écoutez l' $destroyévénement scope :

$scope.$on('$destroy', function iVeBeenDismissed() {
  // say goodbye to your controller here
  // release resources, cancel request...
})

En ngViewparticulier, vous pouvez savoir quand le contenu est chargé via l'événement scope $viewContentLoaded:

$scope.$on('$viewContentLoaded', function readyToTrick() {
  // say hello to your new content here
  // BUT NEVER TOUCHES THE DOM FROM A CONTROLLER
});

Voici un Plunker avec un concept proof (ouvrez la fenêtre de votre console).

Caio Cunha
la source
10
De nos jours, le code qui détruit la portée $ vit sur github.com/angular/angular.js/blob/… . Très utile, merci!
w00t
4
viewContentLoaded ne fonctionne que si vous utilisez un délai d'attente car il est distribué juste avant le chargement du modèle ... les documents disent le contraire, mais ils se réfèrent à raw template: "HTML STRING"lorsqu'il s'agit d'un fichier de modèle, il est chargé en mode asynchrone.
user3338098