AngularJS: Comment puis-je passer des variables entre les contrôleurs?
J'ai deux contrôleurs angulaires:
function Ctrl1($scope) {
$scope.prop1 = "First";
}
function Ctrl2($scope) {
$scope.prop2 = "Second";
$scope.both = Ctrl1.prop1 + $scope.prop2; //This is what I would like to do ideally
}
Je ne peux pas utiliser Ctrl1
à l'intérieur de Ctrl2
car il n'est pas défini. Cependant, si j'essaie de le passer comme ça ...
function Ctrl2($scope, Ctrl1) {
$scope.prop2 = "Second";
$scope.both = Ctrl1.prop1 + $scope.prop2; //This is what I would like to do ideally
}
Je reçois une erreur. Personne ne sait comment faire cela?
Faire
Ctrl2.prototype = new Ctrl1();
Échoue également.
NOTE: ces contrôleurs ne sont pas imbriqués les uns dans les autres.
15 réponses
Une façon de partager des variables entre plusieurs contrôleurs est de créer un service de et de l'injecter dans n'importe quel contrôleur où vous souhaitez l'utiliser.
Exemple de service Simple:
angular.module('myApp', [])
.service('sharedProperties', function () {
var property = 'First';
return {
getProperty: function () {
return property;
},
setProperty: function(value) {
property = value;
}
};
});
L'Utilisation du service dans un contrôleur:
function Ctrl2($scope, sharedProperties) {
$scope.prop2 = "Second";
$scope.both = sharedProperties.getProperty() + $scope.prop2;
}
Ceci est très bien décrit dans ce blog (Leçon 2 et plus en particulier).
J'ai trouvé que si vous souhaitez lier à ces propriétés sur plusieurs contrôleurs, il fonctionne mieux si vous liez à un propriété de l'objet au lieu d'un type primitif (booléen, chaîne, nombre) pour conserver la référence liée.
Exemple: var property = { Property1: 'First' };
au lieu de var property = 'First';
.
UPDATE: pour (espérons-le) rendre les choses plus claires voici un violon {[6] } qui montre un exemple de:
-
liaison à des copies statiques de la valeur partagée (dans myController1)
- liaison à une primitive (chaîne)
- liaison à la propriété d'un objet (enregistrée dans une portée variable)
-
liaison aux valeurs partagées qui mettent à jour l'interface utilisateur lorsque les valeurs sont mises à jour (dans myController2)
- liaison à une fonction qui renvoie une primitive (chaîne)
- Liaison à la propriété de l'objet
- liaison bidirectionnelle à la propriété d'un objet
J'aime illustrer des choses simples par des exemples simples :)
Voici un exemple très simple Service
:
angular.module('toDo',[])
.service('dataService', function() {
// private variable
var _dataObj = {};
// public API
this.dataObj = _dataObj;
})
.controller('One', function($scope, dataService) {
$scope.data = dataService.dataObj;
})
.controller('Two', function($scope, dataService) {
$scope.data = dataService.dataObj;
});
Et voici un exemple très simple Factory
:
angular.module('toDo',[])
.factory('dataService', function() {
// private variable
var _dataObj = {};
// public API
return {
dataObj: _dataObj
};
})
.controller('One', function($scope, dataService) {
$scope.data = dataService.dataObj;
})
.controller('Two', function($scope, dataService) {
$scope.data = dataService.dataObj;
});
Si c'est trop simple, voici un exemple plus élaboré
Aussi voir la réponse ici pour les meilleures pratiques connexes Commentaires
--- je sais que cette réponse n'est pas pour cette question, mais je veux que les gens qui lisent cette question et veulent gérer des Services tels que les usines pour éviter les problèmes----
Pour cela, vous devrez utiliser un Service ou une usine.
Les services sont les meilleures pratiques {[9] } pour partager des données entre des contrôleurs non imbriqués.
Une très très bonne annotation sur ce sujet sur le partage de données est de savoir comment déclarer des objets. J'ai eu de la malchance parce que je suis tombé dedans un piège AngularJS avant que je lis à ce sujet, et je suis très frustré. Laissez-moi vous aider à éviter ce problème.
J'ai lu dans le "ng-book: le livre complet sur AngularJS" que les modèles AngularJS ng créés dans les contrôleurs en tant que données nues sont faux!
Un élément $ scope doit être créé comme ceci:
angular.module('myApp', [])
.controller('SomeCtrl', function($scope) {
// best practice, always use a model
$scope.someModel = {
someValue: 'hello computer'
});
Et pas comme ça:
angular.module('myApp', [])
.controller('SomeCtrl', function($scope) {
// anti-pattern, bare value
$scope.someBareValue = 'hello computer';
};
});
C'est parce qu'il est recommandé(meilleure pratique) pour le DOM (document html) de contenir les appels comme
<div ng-model="someModel.someValue"></div> //NOTICE THE DOT.
C'est très utile pour les contrôleurs imbriqués si vous voulez que votre contrôleur enfant puisse changer un objet à partir du contrôleur parent....
Mais dans votre cas, vous ne voulez pas d'étendues imbriquées, mais il existe un aspect similaire pour obtenir des objets des services vers les contrôleurs.
Disons que vous avez votre service 'Factory' et dans l'espace de retour il y a un objectA qui contient objectB qui contient objectC.
Si à partir de votre contrôleur vous voulez obtenir l'objectC dans votre portée, est une erreur de dire:
$scope.neededObjectInController = Factory.objectA.objectB.objectC;
Ça ne marchera pas... Utilisez plutôt un seul point.
$scope.neededObjectInController = Factory.ObjectA;
Ensuite, dans le DOM, vous pouvez appeler objectC depuis objectA. C'est une bonne pratique liée aux usines, et le plus important, cela aidera à éviter les erreurs inattendues et non capturables.
Solution sans créer de Service, en utilisant $ rootScope:
Pour partager des propriétés entre les contrôleurs d'applications, vous pouvez utiliser Angular $ rootScope. Ceci est une autre option pour partager des données, le mettre afin que les gens savent à ce sujet.
Le moyen préféré de partager certaines fonctionnalités entre les contrôleurs est les Services, pour lire ou modifier une propriété globale que vous pouvez utiliser $rootscope.
var app = angular.module('mymodule',[]);
app.controller('Ctrl1', ['$scope','$rootScope',
function($scope, $rootScope) {
$rootScope.showBanner = true;
}]);
app.controller('Ctrl2', ['$scope','$rootScope',
function($scope, $rootScope) {
$rootScope.showBanner = false;
}]);
Utilisation de $ rootScope dans un modèle (propriétés D'accès avec $ root):
<div ng-controller="Ctrl1">
<div class="banner" ng-show="$root.showBanner"> </div>
</div>
L'échantillon ci-dessus a fonctionné comme un charme. Je viens de faire une modification juste au cas où j'aurais besoin de gérer plusieurs valeurs. J'espère que cela aide!
app.service('sharedProperties', function () {
var hashtable = {};
return {
setValue: function (key, value) {
hashtable[key] = value;
},
getValue: function (key) {
return hashtable[key];
}
}
});
J'ai tendance à utiliser des valeurs, heureux pour quiconque de discuter pourquoi c'est une mauvaise idée..
var myApp = angular.module('myApp', []);
myApp.value('sharedProperties', {}); //set to empty object -
Injectez ensuite la valeur selon un service.
Défini dans ctrl1:
myApp.controller('ctrl1', function DemoController(sharedProperties) {
sharedProperties.carModel = "Galaxy";
sharedProperties.carMake = "Ford";
});
Et accès depuis ctrl2:
myApp.controller('ctrl2', function DemoController(sharedProperties) {
this.car = sharedProperties.carModel + sharedProperties.carMake;
});
Je voudrais contribuer à cette question en soulignant que la façon recommandée de partager des données entre les contrôleurs, et même les directives, est en utilisant des services (usines) comme cela a déjà été souligné, mais aussi je voudrais fournir un exemple pratique de la façon de cela devrait être fait.
Voici le plunker de travail: http://plnkr.co/edit/Q1VdKJP2tpvqqJL1LF6m?p=info
Tout d'Abord, créer votre service, qui permettra à votre données partagées :
app.factory('SharedService', function() {
return {
sharedObject: {
value: '',
value2: ''
}
};
});
Ensuite, injectez-le simplement sur vos contrôleurs et récupérez les données partagées sur votre portée:
app.controller('FirstCtrl', function($scope, SharedService) {
$scope.model = SharedService.sharedObject;
});
app.controller('SecondCtrl', function($scope, SharedService) {
$scope.model = SharedService.sharedObject;
});
app.controller('MainCtrl', function($scope, SharedService) {
$scope.model = SharedService.sharedObject;
});
Vous pouvez aussi le faire pour vos directives , cela fonctionne de la même manière:
app.directive('myDirective',['SharedService', function(SharedService){
return{
restrict: 'E',
link: function(scope){
scope.model = SharedService.sharedObject;
},
template: '<div><input type="text" ng-model="model.value"/></div>'
}
}]);
J'espère que cette réponse pratique et propre peut être utile à quelqu'un.
L'exemple suivant montre comment passer des variables entre frères et sœurs les contrôleurs et effectuent une action lorsque la valeur change.
Exemple de cas d'utilisation: vous avez un filtre dans une barre latérale qui modifie le contenu d'une autre vue.
angular.module('myApp', [])
.factory('MyService', function() {
// private
var value = 0;
// public
return {
getValue: function() {
return value;
},
setValue: function(val) {
value = val;
}
};
})
.controller('Ctrl1', function($scope, $rootScope, MyService) {
$scope.update = function() {
MyService.setValue($scope.value);
$rootScope.$broadcast('increment-value-event');
};
})
.controller('Ctrl2', function($scope, MyService) {
$scope.value = MyService.getValue();
$scope.$on('increment-value-event', function() {
$scope.value = MyService.getValue();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<h3>Controller 1 Scope</h3>
<div ng-controller="Ctrl1">
<input type="text" ng-model="value"/>
<button ng-click="update()">Update</button>
</div>
<hr>
<h3>Controller 2 Scope</h3>
<div ng-controller="Ctrl2">
Value: {{ value }}
</div>
</div>
Ne pourriez-vous pas également faire de la propriété une partie du parent scopes?
$scope.$parent.property = somevalue;
Je ne dis pas que c'est juste mais ça marche.
Ah, avoir un peu de ce nouveau truc comme une autre alternative. C'est localstorage, et fonctionne là où angular fonctionne. Vous êtes les bienvenus. (Mais vraiment, merci le gars)
Https://github.com/gsklee/ngStorage
Définissez vos valeurs par défaut:
$scope.$storage = $localStorage.$default({
prop1: 'First',
prop2: 'Second'
});
Accéder aux valeurs:
$scope.prop1 = $localStorage.prop1;
$scope.prop2 = $localStorage.prop2;
Stocke les valeurs
$localStorage.prop1 = $scope.prop1;
$localStorage.prop2 = $scope.prop2;
N'oubliez pas d'injecter ngStorage dans votre application et $ localStorage dans votre contrôleur.
Vous pouvez le faire avec des services ou des usines. Ils sont essentiellement les mêmes à part pour certaines différences fondamentales. J'ai trouvé cette explication sur thinkster.io pour être plus facile à suivre. Simple, et efficace.
Il y a deux façons de le faire
1) Utiliser le service get / set
2)
$scope.$emit('key', {data: value}); //to set the value
$rootScope.$on('key', function (event, data) {}); // to get the value
Deuxième Approche:
angular.module('myApp', [])
.controller('Ctrl1', ['$scope',
function($scope) {
$scope.prop1 = "First";
$scope.clickFunction = function() {
$scope.$broadcast('update_Ctrl2_controller', $scope.prop1);
};
}
])
.controller('Ctrl2', ['$scope',
function($scope) {
$scope.prop2 = "Second";
$scope.$on("update_Ctrl2_controller", function(event, prop) {
$scope.prop = prop;
$scope.both = prop + $scope.prop2;
});
}
])
Html :
<div ng-controller="Ctrl2">
<p>{{both}}</p>
</div>
<button ng-click="clickFunction()">Click</button>
Pour plus de détails, voir plunker :
Si vous ne voulez pas faire de service, vous pouvez faire comme ça.
var scope = angular.element("#another ctrl scope element id.").scope();
scope.plean_assign = some_value;
Outre $rootScope et services, il existe une solution alternative propre et facile pour étendre angular pour ajouter les données partagées:
Dans les contrôleurs:
angular.sharedProperties = angular.sharedProperties
|| angular.extend(the-properties-objects);
Ces propriétés appartiennent à l'objet' angular', séparé des étendues, et peuvent être partagées dans les étendues et les services.
1 Avantage de celui-ci que vous n'avez pas à injecter l'objet: ils sont accessibles n'importe où immédiatement après votre defination!