web-dev-qa-db-fra.com

portée et instanciation du contrôleur avec le routeur ui

Je ne sais pas quand les contrôleurs sont instanciés. En outre, comment les contrôleurs sont-ils instanciés lors de l'imbrication des états. Je peux être confus sur la façon dont la portée est attachée à la vue et au contrôleur, c'est-à-dire si chaque vue obtient son propre contrôleur et sa propre portée ou partagent-ils la même portée.

Quelqu'un peut-il expliquer quand les contrôleurs sont instanciés? Sous les routes imbriquées, toutes les vues partagent-elles un contrôleur et une étendue? Que se passe-t-il lorsque je change d'état et reviens à un état où un autre contrôleur est-il instancié?

Voici mes itinéraires (fichier de configuration):

.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'
      }
    }
  })
25
eNddy

Pour obtenir des réponses encore plus détaillées, nous pouvons/devons observer le code source et consulter la documentation . Permettez-moi d'essayer d'expliquer les trois questions (et de citer également du code et de la doc).

1. Quand les contrôleurs sont-ils instanciés?

Ici, nous pouvons observer le code de la directive ui-view:

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

Les contrôleurs sont liés aux vues . Ces views, qui sont définis à l'intérieur d'une .state() en tant qu'objet views:

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

Ainsi, chaque fois que la vue (le ui-view) Est remplie de paramètres définis à l'intérieur d'une vue d'état, elle agit presque comme une directive standard, mais améliorée .

1) Le modèle est trouvé,
2) Les résolutions sont résolues
...
x) Le contrôleur est instancié ...

Les cibles de vue (directives ui-view) Peuvent utiliser des noms et peuvent être remplies par différents états de la hiérarchie.

Cela pourrait signifier qu'il pourrait y avoir un contenu à l'intérieur d'une vue (par exemple titre ) , défini par parent ainsi que remplacé par enfant

// 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"
  },
  ...
}

La définition d'état ci-dessus permet (chaque fois que nous passons entre ces deux états) :

  • La $state.go('parent') - la vue (modèle, contrôleur ...) définie dans 'title@parent' : { ...} Sera injectée dans la cible ui-view="title" Et instanciée comme décrit ci-dessus

  • La fonction $state.go('parent.child') - presque la même, seule la vue sera prise à partir de la définition de l'état/vue enfant 'title' : { ...}. Cela remplacera le contenu du ui-view="title" Et sera instancié comme décrit ci-dessus

Cela se produira à chaque fois que nous passerons de parent à enfant et d'enfant à parent .

2. Sous les routes imbriquées, toutes les vues partagent-elles un contrôleur et une portée?

Une réponse simple est [~ # ~] non [~ # ~] , il y a non partage commun.

En fait, chaque contrôleur a sa propre portée , celle qui est créé à partir de la portée de la vue parent. Tout d'abord la documentation:

Qu'est-ce que les États enfants héritent des États parents?

...

Héritage d'étendue par hiérarchie de vues uniquement

Gardez à l'esprit que les propriétés d'étendue n'héritent de la chaîne d'état que si les vues de vos états sont imbriquées. L'héritage des propriétés d'étendue n'a rien à voir avec l'imbrication de vos états et tout à voir avec l'imbrication de vos vues (modèles).

Il est tout à fait possible que vous ayez des états imbriqués dont les modèles remplissent les vues d'interface utilisateur à divers emplacements non imbriqués de votre site. Dans ce scénario, vous ne pouvez pas vous attendre à accéder aux variables d'étendue des vues d'état parent dans les vues des états enfants.

Donc, chaque fois que notre controller (enfin la vue avec le modèle, le contrôleur ...) injecté dans la cible du parent ui-view="..." il obtient la portée héritée:

newScope = scope.$new();

Cela en un mot signifie que les objets JS (par exemple scope.Model = {}) peuvent être partagés entre l'enfant et le parent.

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

Cependant , les types Javascript de base ne sont pas transmis par référence, et leurs valeurs ne sont donc pas automatiquement synchronisées entre portées:

// 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

Il vaut la peine d'en lire plus sur l'héritage prototypique ici:
Quelles sont les nuances de l'héritage prototypique/prototypique de portée dans AngularJS?

3. Que se passe-t-il lorsque je change d'état et reviens à un état - un autre contrôleur est-il instancié?

Ça dépend.

Si la sous-vue parent (rappelez-vous ui-view="title" Ci-dessus) est remplacée par la vue enfant, puis elle est recréée (transition de de l'enfant au parent) - un tel contrôleur sera réinitialisé (voir ci-dessus).

Mais quand nous parlons de la vue parent principale (généralement sans nom) , ce qui représente le parent (par exemple la vue sans nom ci-dessous avec le contrôleur 'ParentMainCtrl')

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

Nous pouvons alors être sûrs qu'un tel contrôleur n'est PAS ré-instancié. Il vit pendant la durée de vie de tous ses enfants, plus celui d'un parent (aucun état enfant sélectionné) .

Pour recharger cette vue/contrôleur, nous devons utiliser une option reload

$ state.go (to, params, options)

... options Objet options. Les options sont les suivantes:

  • ...
  • recharger - {boolean=false}, si true force la transition même si l'état ou les paramètres n'ont pas changé, c'est-à-dire un rechargement du même état. Il diffère de reloadOnSearch car vous l'utilisez lorsque vous souhaitez forcer un rechargement lorsque tout est identique, y compris les paramètres de recherche.

J'espère que ça aidera un peu. Pour plus d'informations, consultez ces ressources:

33
Radim Köhler

Les contrôleurs sont instanciés lorsque les vues correspondantes sont chargées pour la première fois.

Par exemple, si vous avez 3 onglets associés à 3 contrôleurs - le contrôleur associé à la vue par défaut instancie d'abord. Ensuite, lorsque vous chargez les autres vues, les contrôleurs associés sont également instanciés.

Mais fait intéressant, une fois qu'une vue est chargée dans le DOM - elle est mise en cache par défaut. Lorsqu'une vue est éloignée de, son élément est laissé dans le DOM et sa portée est déconnectée du cycle $ watch. Lorsque vous accédez à une vue déjà mise en cache, sa portée est ensuite reconnectée et l'élément existant qui a été laissé dans le DOM devient la vue active.

2

Les contrôleurs sont instanciés chaque fois que vous visitez l'état spécifique. Par exemple, lorsque vous visitez app.pincode.pincodeLogin pour la première fois, un AppController et deux PincodeControllers sont construits, chacun avec sa propre vue en supposant que vous avez les bons modèles. Passer à 'app.pincode.settings' détruirait le contrôleur le plus intérieur et le remplacerait par un nouveau, bien que les deux contrôleurs supérieurs de la hiérarchie ne soient pas touchés. Les étendues suivent le modèle d'héritage d'AngularJS standard, elles ne sont pas isolées.

Vous voudrez probablement supprimer les contrôleurs dans les sous-états (et gérer la logique métier dans le contrôleur parent) ou avoir un contrôleur distinct pour chaque état - le même contrôleur pour différents modèles et vues est généralement un signe de mauvaise conception.

2
Pyetras