Qual é o ciclo de vida de um controlador AngularJS?

199

Alguém pode esclarecer qual é o ciclo de vida de um controlador AngularJS?

  • Um controlador é um singleton ou criado / destruído sob demanda?
  • Neste último caso, o que desencadeia a criação / destruição do controlador?

Considere o exemplo abaixo:

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

por exemplo:

No exemplo acima, quando eu navego para /users/1, o usuário 1 é carregado e definido como $scope.

Então, quando eu navego para /users/2, o usuário 2 é carregado. A mesma instância é UserEditorCtrlreutilizada ou uma nova instância é criada?

  • Se é uma nova instância, o que desencadeia a destruição da primeira instância?
  • Se for reutilizado, como isso funciona? (ou seja, o método para carregar os dados parece ser executado na criação do controlador)
Marty Pitt
fonte

Respostas:

227

Bem, na verdade a questão é qual é o ciclo de vida de um ngViewcontrolador.

Controladores não são singletons. Qualquer um pode criar um novo controlador e nunca é destruído automaticamente. O fato é que geralmente está vinculado ao ciclo de vida de seu escopo subjacente. O controlador não é destruído automaticamente sempre que seu escopo é destruído. No entanto, depois de destruir um escopo subjacente, seu controlador é inútil (pelo menos, por design, deveria ser).

Respondendo à sua pergunta específica, uma ngViewdiretiva (assim como a ngControllerdiretiva) sempre criará um novo controlador e um novo escopo sempre que uma navegação acontecer. E o último escopo também será destruído .

O ciclo de vida "eventos" é bastante simples. Seu "evento de criação" é a construção do seu próprio controlador. Apenas execute seu código. Para saber quando fica inútil ( "evento de destruição" ), ouça o $destroyevento de escopo :

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

Para ngViewespecificamente, você pode saber quando o conteúdo é carregado através do evento de escopo $viewContentLoaded:

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

Aqui está um Plunker com uma prova de conceito (abra a janela do console).

Caio Cunha
fonte
10
Atualmente, o código que destrói o escopo $ está em github.com/angular/angular.js/blob/… . Muito útil, obrigado!
W00t
4
O viewContentLoaded só funciona se você usar um tempo limite porque ele é despachado logo antes do carregamento do modelo ... os documentos dizem o contrário, mas estão se referindo ao raw template: "HTML STRING"quando é um arquivo de modelo carregado de forma assíncrona.
user3338098