Instanciação de escopo e controlador com roteador ui

Estou confuso sobre quando os controladores são instanciados. Além disso, como os controladores são instanciados quando os estados de aninhamento. Eu posso estar confuso como o escopo é anexado à view e ao controller, ou seja, se cada view recebe seu próprio controller e scope ou eles compartilham o mesmo escopo.

Alguém pode explicar quando os controladores são instanciados? Em rotas aninhadas, todas as visualizações compartilham um controlador e um escopo? O que acontece quando eu troco estados e volto para um estado que outro controlador é instanciado?

Abaixo estão minhas rotas (arquivo de configuração):

.config (googleAnalyticsCordovaProvider, $stateProvider, $urlRouterProvider, IdleProvider, KeepaliveProvider) -> $stateProvider .state('app', { url: '/app', abstract: true, templateUrl: 'templates/menu.html', controller: 'AppController' }) .state('app.pincode', { url: '/pincode', views: { menuContent: { templateUrl: 'templates/pincode-yield.html', controller: 'PincodeController' } } }) .state('app.pincode.create', { url: '/create', views: { pincode: { templateUrl: 'templates/pincode-create.html', controller: 'PincodeController' } } }) .state('app.pincode.pincodeLogin', { url: '/login', views: { pincode: { templateUrl: 'templates/pincode-login.html', controller: 'PincodeController' } } }) .state('app.pincode.settings', { url: '/settings', views: { pincode: { templateUrl: 'templates/settings.html', controller: 'PincodeController' } } }) 

Para obter respostas ainda mais detalhadas, podemos / devemos observar o código-fonte e verificar a documentação . Deixe-me tentar explicar todas as três questões (e também citar do código e do doc).

1. Quando os controladores são instanciados?

Aqui podemos observar o código da diretiva ui-view :

[$ViewDirective.$inject = \['$state', '$injector', '$uiViewScroll', '$interpolate'\];][1]

Os controladores estão relacionados a visualizações . Essas views , que são definidas dentro de um .state() como o object views :

 .state('...', { // The view definition views : { '' : { template: ... controller: ... resolve: .. } }, resolve: ... } 

Assim, sempre que a visualização (a visualização de ui-view ) estiver preenchida com configurações definidas dentro de uma visualização de estado, ela atuará quase como uma diretiva padrão, mas aprimorada .

1) Modelo encontrado,
2) As resoluções são resolvidas

x) O controlador é instanciado …

Os alvos de exibição (diretivas de ui-view ) podem usar nomes e podem ser preenchidos por diferentes estados na hierarquia.

Isso poderia significar que poderia haver um conteúdo dentro de uma visão (por exemplo, título ) , definido pelo pai e também substituído pelo filho.

 // parent .state('parent', { views : { '' : {...} // the main parent view, with ui-view="title" 'title@parent' : { ...} // here we go and fill parent's ui-view="title" }, ... } // child .state('parent.child', { views : { 'title' : { ...} // here we change the parent's target ui-view="title" }, ... } 

A definição de estado acima irá (sempre que fizermos a transição entre esses dois estados) :

  • O $state.go('parent') – a view (template, controller …) definida em 'title@parent' : { ...} será injetada no destino ui-view="title" e instanciada conforme descrito acima

  • O $state.go('parent.child') – quase o mesmo, apenas a view será tirada do estado child / view defintion 'title' : { ...} . Isso replaceá o conteúdo da ui-view="title" e será instanciado conforme descrito acima

Isso acontecerá toda vez que formos de pais para filhos e de filhos para pais .

2. Em rotas aninhadas, todas as visualizações compartilham um controlador e um escopo?

Uma resposta simples é NÃO , não compartilhamento comum.

De fato, cada controlador possui seu próprio escopo , aquele que é criado a partir do escopo da visão pai. Em primeiro lugar a documentação:

O que os estados de crianças herdam dos pais?

Herança de escopo somente pela hierarquia de exibição

Tenha em mente que as propriedades do escopo somente herdam a cadeia de estados se as exibições de seus estados estiverem aninhadas. Herança de propriedades de escopo não tem nada a ver com o aninhamento de seus estados e tudo a ver com o aninhamento de suas exibições (modelos).

É totalmente possível que você tenha estados nesteds cujos modelos preencham visualizações de ui em vários locais não nesteds em seu site. Nesse cenário, você não pode esperar acessar as variables ​​de escopo das exibições de estado pai nas exibições dos estados filhos.

Então, sempre que o nosso controller (bem a view com template, controller …) é injetado no target do pai ui-view="..." ele recebe escopo herdado:

 newScope = scope.$new(); 

Em suma, significa que os objects JS (por exemplo, scope.Model = {} ) podem ser compartilhados entre pai e filho.

 $scope.Model.id = 1; // will refer to the same id in both parent & child 

No entanto , os tipos Javascript básicos não são passados ​​por referência e, portanto, seus valores não são automaticamente sincronizados entre os escopos:

 // set in parent $scope.id = 1; // in child after inherted still === 1 $scope.id = 2; // now 2 for a child, different value in parent - still === 1 

Vale a pena ler mais sobre inheritance prototípica aqui:
Quais são as nuances do escopo protótipo / inheritance prototípica no AngularJS?

3. O que acontece quando eu troco de estado e volto para um estado – outro controlador é instanciado?

Depende.

Se a sub-view pai (lembre ui-view="title" se de ui-view="title" acima) é substituída pela view child, e então é recriada (transição de child para parent) – tal controller será reinicializado (discutido acima).

Mas quando falamos sobre a visualização pai principal (geralmente sem nome) , que representa o pai (por exemplo, a visão não nomeada abaixo com o controlador ‘ParentMainCtrl’)

 .state('parent', { views : { '' : { // // the main parent view controller: 'ParentMainCtrl', } 'title@parent' 'tooltip@parent' }, 

Então podemos ter certeza de que tal controlador NÃO é re-instanciado. Ele vive durante o tempo de vida de todos os seus filhos, mais um pai (nenhum estado filho selecionado) .

Para recarregar esta view / controller, nós temos que usar uma opção reload

$ state.go (para, params, opções)

… opções Opções object. As opções são:

  • reload{boolean=false} , se true forçará a transição mesmo que o estado ou parâmetros não tenham mudado, também conhecido como recarregamento do mesmo estado. Ele difere de reloadOnSearch porque você usaria isso quando quiser forçar um recarregamento quando tudo for o mesmo, incluindo parâmetros de pesquisa.

Espero que ajude um pouco. Para mais informações, confira estes resources:

  • Estados nesteds e exibições aninhadas
  • Múltiplas exibições nomeadas
  • Referência da API
  • State.js do aplicativo de exemplo – eu diria que o melhor pedaço de código já documentado

Os controladores são instanciados sempre que você visita o estado específico. Por exemplo, ao visitar app.pincode.pincodeLogin pela primeira vez, um AppController e dois PincodeControllers são construídos, cada um com sua própria visão, supondo que você tenha os modelos corretos. Mudar para 'app.pincode.settings' destruiria o controlador mais interno e o replaceia por um novo, embora os dois controladores mais altos na hierarquia não fossem tocados. Os escopos seguem o padrão de inheritance padrão do AngularJS, eles não são isolados.

Você provavelmente desejaria remover os controladores nos estados de sub (e manipular a lógica de negócios no controlador pai) ou ter um controlador distinto para cada estado – o mesmo controlador para modelos e visualizações diferentes geralmente é um sinal de design incorreto.

Os controladores são instanciados quando as visualizações correspondentes são carregadas pela primeira vez.

Por exemplo, se você tiver 3 guias associadas a 3 controladores – então o controlador associado à visualização padrão instancia primeiro. Em seguida, quando você carrega as outras visualizações, os controladores associados também são instanciados.

Mas, curiosamente, uma vez que uma visão é carregada no DOM – ela é armazenada em cache por padrão. Quando uma visualização é navegada para longe, seu elemento é deixado no DOM e seu escopo é desconectado do ciclo de exibição $. Ao navegar para uma exibição que já está em cache, seu escopo é reconectado e o elemento existente que foi deixado no DOM torna-se a exibição ativa.