J'ai une vue parent abstraite destinée à partager un contrôleur avec ses vues imbriquées.
.state('edit', {
abstract: true,
url: '/home/edit/:id',
templateUrl: 'app/templates/editView.html',
controller: 'editController'
})
.state('edit.details', {
url: '/details',
templateUrl: 'app/templates/editDetailsView.html'
})
.state('edit.info', {
url: '/info',
templateUrl: 'app/templates/editInfoView.html'
})
Le routage fonctionne comme prévu.
Le problème est que lorsque je mets à jour une variable $scope
à partir de l'une des vues imbriquées, la modification n'est pas reflétée dans la vue. Quand je fais la même chose à partir de la vue parent, cela fonctionne bien. Ce n'est pas une situation qui nécessite un $apply
.
À mon avis, une nouvelle instance de editController
est en cours de création pour chaque vue, mais je ne sais pas pourquoi ni comment la résoudre.
La question ici serait liée à ce Q & A: Comment partager des données $ scope entre des états dans angularjs ui-router? .
La façon de le résoudre est cachée dans le:
Dans AngularJS, une portée enfant hérite normalement de sa portée parent de manière prototypique.
...Avoir un '.' dans vos modèles garantira que l’héritage prototype est en jeu.
// So, use
<input type="text" ng-model="someObj.prop1">
// rather than
<input type="text" ng-model="prop1">.
Et aussi ça
Gardez à l'esprit que les propriétés de portée n'héritent en aval de la chaîne d'états que si les vues de vos états sont imbriquées. L'héritage des propriétés de portée n'a rien à voir avec l'imbrication de vos états et tout ce qui a trait à l'imbrication de vos vues (modèles).
Il est tout à fait possible que vous ayez des états imbriqués dont les modèles remplissent des vues UI à divers emplacements non imbriqués au sein 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 d'états enfants.
Ayant cela, nous devrions le faire dans le contrôleur de montage
controller('editController', function ($scope) {
$scope.Model = $scope.Model || {SomeProperty : "xxx"};
})
Et nous pouvons même réutiliser ce controller: 'editController'
_ (nous ne pouvons pas le faire, car le $ scope.Model sera présent - grâce à l'héritage)
.state('edit', {
abstract: true,
url: '/home/edit/:id',
templateUrl: 'app/templates/editView.html',
controller: 'editController'
})
.state('edit.details', {
url: '/details',
templateUrl: 'app/templates/editDetailsView.html',
controller: 'editController'
})
.state('edit.info', {
url: '/info',
templateUrl: 'app/templates/editInfoView.html',
controller: 'editController'
})
Maintenant, le même contrôleur sera instancié plusieurs fois (parent tous les enfants) mais le $scope.Model
sera lancé une seule fois (à l'intérieur du parent) et disponible partout
Cochez cette exemple de travail similaire ici
Basé sur un commentaire de PilotBob
Est-il possible de faire cela en utilisant le modèle
controllerAs
donnant à l'état enfant son propre contrôleur?
J'ai décidé d'ajouter une autre solution, en utilisant controllerAs
tout en conservant le ci-dessus/concept original
Il y a un plongeur de travail
Les états auraient maintenant différents contrôleurs et l'état parent le nommera "parentCtrl" (à NE PAS écraser dans une portée enfant avec un contrôleur enfant)}
.state("main", {
controller:'mainController',
controllerAs: "parentCtrl",
...
.state("main.1", {
parent: 'main',
controller:'child1Controller',
controllerAs: "ctrl",
...
.state("main.2", {
parent: 'main',
controller:'child2Controller',
controllerAs: "ctrl",
...
Et ce sont des contrôleurs:
.controller('mainController', function ($scope) {
this.Model = {Name : "yyy"};
})
.controller('child1Controller', function ($scope) {
$scope.Model = $scope.parentCtrl.Model;
})
.controller('child2Controller', function ($scope) {
$scope.Model = $scope.parentCtrl.Model;
})
Vérifiez-le en action ici
Une autre alternative en utilisant resolve
.state('edit', {
abstract: true,
url: '/home/edit/:id',
templateUrl: 'app/templates/editView.html',
controller: 'editController',
resolve: {
baseData: function() {
return {};
}
}
})
.state('edit.details', {
url: '/details',
templateUrl: 'app/templates/editDetailsView.html',
controller: 'editController'
})
.state('edit.info', {
url: '/info',
templateUrl: 'app/templates/editInfoView.html',
controller: 'editController'
})
.controller('editController', function (baseData) {
baseData.foo = baseData.foo || 'bar';
});
Dans le contrôleur enfant, vous pouvez faire:
angular.extend($scope, $scope.$parent)
Si le contrôleur est utilisé avec un alias, par ex. 'vm' tu peux faire:
let vm = angular.extend(this, $scope.$parent.vm);