Partage des données entre les contrôleurs AngularJS
j'essaie de partager les données entre les contrôleurs. Use-case est un formulaire à plusieurs étapes, les données saisies dans une entrée sont ensuite utilisées dans plusieurs emplacements d'affichage à l'extérieur du contrôleur d'origine. Code ci-dessous et dans jsfiddle ici .
HTML
<div ng-controller="FirstCtrl">
<input type="text" ng-model="FirstName"><!-- Input entered here -->
<br>Input is : <strong>{{FirstName}}</strong><!-- Successfully updates here -->
</div>
<hr>
<div ng-controller="SecondCtrl">
Input should also be here: {{FirstName}}<!-- How do I automatically updated it here? -->
</div>
JS
// declare the app with no dependencies
var myApp = angular.module('myApp', []);
// make a factory to share data between controllers
myApp.factory('Data', function(){
// I know this doesn't work, but what will?
var FirstName = '';
return FirstName;
});
// Step 1 Controller
myApp.controller('FirstCtrl', function( $scope, Data ){
});
// Step 2 Controller
myApp.controller('SecondCtrl', function( $scope, Data ){
$scope.FirstName = Data.FirstName;
});
Toute aide est grandement appréciée.
9 réponses
une solution simple est que votre usine rende un objet et laisse vos contrôleurs travailler avec une référence au même objet:
JS:
// declare the app with no dependencies
var myApp = angular.module('myApp', []);
// Create the factory that share the Fact
myApp.factory('Fact', function(){
return { Field: '' };
});
// Two controllers sharing an object that has a string in it
myApp.controller('FirstCtrl', function( $scope, Fact ){
$scope.Alpha = Fact;
});
myApp.controller('SecondCtrl', function( $scope, Fact ){
$scope.Beta = Fact;
});
HTML:
<div ng-controller="FirstCtrl">
<input type="text" ng-model="Alpha.Field">
First {{Alpha.Field}}
</div>
<div ng-controller="SecondCtrl">
<input type="text" ng-model="Beta.Field">
Second {{Beta.Field}}
</div>
Demo: http://jsfiddle.net/HEdJF /
quand les applications deviennent plus grandes, plus complexes et plus difficiles à tester, vous pourriez ne pas vouloir exposer l'objet entier de la
myApp.factory('Data', function () {
var data = {
FirstName: ''
};
return {
getFirstName: function () {
return data.FirstName;
},
setFirstName: function (firstName) {
data.FirstName = firstName;
}
};
});
avec cette approche, il appartient aux contrôleurs consommateurs de mettre à jour l'usine avec de nouvelles valeurs, et de surveiller les changements pour les obtenir:
myApp.controller('FirstCtrl', function ($scope, Data) {
$scope.firstName = '';
$scope.$watch('firstName', function (newValue, oldValue) {
if (newValue !== oldValue) Data.setFirstName(newValue);
});
});
myApp.controller('SecondCtrl', function ($scope, Data) {
$scope.$watch(function () { return Data.getFirstName(); }, function (newValue, oldValue) {
if (newValue !== oldValue) $scope.firstName = newValue;
});
});
HTML:
<div ng-controller="FirstCtrl">
<input type="text" ng-model="firstName">
<br>Input is : <strong>{{firstName}}</strong>
</div>
<hr>
<div ng-controller="SecondCtrl">
Input should also be here: {{firstName}}
</div>
je préfère ne pas utiliser $watch
pour cela. Au lieu d'assigner l'ensemble du service à la portée d'un contrôleur, vous pouvez assigner seulement les données.
JS:
var myApp = angular.module('myApp', []);
myApp.factory('MyService', function(){
return {
data: {
firstName: '',
lastName: ''
}
// Other methods or objects can go here
};
});
myApp.controller('FirstCtrl', function($scope, MyService){
$scope.data = MyService.data;
});
myApp.controller('SecondCtrl', function($scope, MyService){
$scope.data = MyService.data;
});
HTML:
<div ng-controller="FirstCtrl">
<input type="text" ng-model="data.firstName">
<br>Input is : <strong>{{data.firstName}}</strong>
</div>
<hr>
<div ng-controller="SecondCtrl">
Input should also be here: {{data.firstName}}
</div>
alternativement vous pouvez mettre à jour les données de service avec une méthode directe.
JS:
// A new factory with an update method
myApp.factory('MyService', function(){
return {
data: {
firstName: '',
lastName: ''
},
update: function(first, last) {
// Improve this method as needed
this.data.firstName = first;
this.data.lastName = last;
}
};
});
// Your controller can use the service's update method
myApp.controller('SecondCtrl', function($scope, MyService){
$scope.data = MyService.data;
$scope.updateData = function(first, last) {
MyService.update(first, last);
}
});
il y a plusieurs façons de partager les données entre les contrôleurs
- à l'aide des services
- en utilisant $state.les services de go transit
- à l'aide de stateparams
- utilisant rootscope
explication de chaque méthode:
-
Je ne vais pas m'expliquer comme cela a déjà été expliqué par quelqu'un
-
utilisant
$state.go
$state.go('book.name', {Name: 'XYZ'}); // then get parameter out of URL $state.params.Name;
-
$stateparam
fonctionne d'une manière similaire à$state.go
, vous le Passez comme objet à partir de sender controller et collect dans receiver controller en utilisant stateeparam -
utilisant
$rootscope
(a) envoi de données de l'enfant au contrôleur parent
$scope.Save(Obj,function(data) { $scope.$emit('savedata',data); //pass the data as the second parameter }); $scope.$on('savedata',function(event,data) { //receive the data as second parameter });
b) transmission de données du parent à l'enfant contrôleur
$scope.SaveDB(Obj,function(data){ $scope.$broadcast('savedata',data); }); $scope.SaveDB(Obj,function(data){`enter code here` $rootScope.$broadcast('saveCallback',data); });
j'ai créé une usine qui contrôle la portée partagée entre le modèle de chemin de route, de sorte que vous pouvez maintenir les données partagées juste lorsque les utilisateurs naviguent dans le même chemin parent de route.
.controller('CadastroController', ['$scope', 'RouteSharedScope',
function($scope, routeSharedScope) {
var customerScope = routeSharedScope.scopeFor('/Customer');
//var indexScope = routeSharedScope.scopeFor('/');
}
])
ainsi, si l'utilisateur va à un autre chemin de route, par exemple '/Support', les données partagées pour le chemin '/client' seront automatiquement détruites. Mais si, au lieu de cela, l'utilisateur va sur des chemins 'enfant', comme '/ Customer/1 'ou'/Customer / list ' le champ d'application ne sera pas détruire.
vous pouvez voir un échantillon ici: http://plnkr.co/edit/OL8of9
il y a plusieurs façons de partager des données entre les contrôleurs
- services angulaires
- $diffusion, $émettent de la méthode
- Parent à l'enfant contrôleur de communication
- $rootscope
comme nous le savons $rootscope
n'est pas préférable pour le transfert de données ou la communication parce qu'il s'agit d'une portée globale qui est disponible pour l'ensemble de l'application
Pour le partage de données entre Angular Js contrôleurs Angulaire des services de meilleures pratiques, par exemple. .factory
, .service
Au lieu de référence
en cas de transfert de données du parent au contrôleur enfant, vous pouvez accéder directement aux données du parent dans le contrôleur enfant via $scope
Si vous utilisez ui-router
, alors vous pouvez utiliser $stateParmas
pour passer des paramètres d'url id
, name
, key
, etc
$broadcast
est également une bonne façon de transférer des données entre les contrôleurs de parent à enfant et $emit
pour transférer des données de l'enfant aux contrôleurs de parent
HTML
<div ng-controller="FirstCtrl">
<input type="text" ng-model="FirstName">
<br>Input is : <strong>{{FirstName}}</strong>
</div>
<hr>
<div ng-controller="SecondCtrl">
Input should also be here: {{FirstName}}
</div>
JS
myApp.controller('FirstCtrl', function( $rootScope, Data ){
$rootScope.$broadcast('myData', {'FirstName': 'Peter'})
});
myApp.controller('SecondCtrl', function( $rootScope, Data ){
$rootScope.$on('myData', function(event, data) {
$scope.FirstName = data;
console.log(data); // Check in console how data is coming
});
});
Consultez "donné 1519490920" lien pour en savoir plus à propos de $broadcast
il y a une autre façon sans utiliser $watch, en utilisant angular.copie:
var myApp = angular.module('myApp', []);
myApp.factory('Data', function(){
var service = {
FirstName: '',
setFirstName: function(name) {
// this is the trick to sync the data
// so no need for a $watch function
// call this from anywhere when you need to update FirstName
angular.copy(name, service.FirstName);
}
};
return service;
});
// Step 1 Controller
myApp.controller('FirstCtrl', function( $scope, Data ){
});
// Step 2 Controller
myApp.controller('SecondCtrl', function( $scope, Data ){
$scope.FirstName = Data.FirstName;
});
Il y a plusieurs façons de le faire.
-
événements - déjà bien expliqué.
-
routeur ui-expliqué ci-dessus.
- Service - avec la méthode de mise à jour affichée ci-dessus
- BAD - à L'affût des changements.
- un Autre parent de l'enfant plutôt que émettent et qu'il est diffusé -
*
<superhero flight speed strength> Superman is here! </superhero>
<superhero speed> Flash is here! </superhero>
*
app.directive('superhero', function(){
return {
restrict: 'E',
scope:{}, // IMPORTANT - to make the scope isolated else we will pollute it in case of a multiple components.
controller: function($scope){
$scope.abilities = [];
this.addStrength = function(){
$scope.abilities.push("strength");
}
this.addSpeed = function(){
$scope.abilities.push("speed");
}
this.addFlight = function(){
$scope.abilities.push("flight");
}
},
link: function(scope, element, attrs){
element.addClass('button');
element.on('mouseenter', function(){
console.log(scope.abilities);
})
}
}
});
app.directive('strength', function(){
return{
require:'superhero',
link: function(scope, element, attrs, superHeroCtrl){
superHeroCtrl.addStrength();
}
}
});
app.directive('speed', function(){
return{
require:'superhero',
link: function(scope, element, attrs, superHeroCtrl){
superHeroCtrl.addSpeed();
}
}
});
app.directive('flight', function(){
return{
require:'superhero',
link: function(scope, element, attrs, superHeroCtrl){
superHeroCtrl.addFlight();
}
}
});
Je ne sais pas où j'ai trouvé ce modèle mais pour partager des données entre les contrôleurs et réduire $rootScope et $scope cela fonctionne très bien. Cela rappelle une réplication de données où vous avez des éditeurs et des abonnés. Espérons que cela aide.
Le Service:
(function(app) {
"use strict";
app.factory("sharedDataEventHub", sharedDataEventHub);
sharedDataEventHub.$inject = ["$rootScope"];
function sharedDataEventHub($rootScope) {
var DATA_CHANGE = "DATA_CHANGE_EVENT";
var service = {
changeData: changeData,
onChangeData: onChangeData
};
return service;
function changeData(obj) {
$rootScope.$broadcast(DATA_CHANGE, obj);
}
function onChangeData($scope, handler) {
$scope.$on(DATA_CHANGE, function(event, obj) {
handler(obj);
});
}
}
}(app));
le contrôleur qui reçoit les nouvelles données, qui est L'éditeur ferait quelque chose comme cela..
var someData = yourDataService.getSomeData();
sharedDataEventHub.changeData(someData);
le contrôleur qui est aussi en utilisant ces nouvelles données, qui est appelé L'abonné ferait quelque chose comme cela...
sharedDataEventHub.onChangeData($scope, function(data) {
vm.localData.Property1 = data.Property1;
vm.localData.Property2 = data.Property2;
});
cela fonctionnera pour n'importe quel scénario. Ainsi, lorsque le contrôleur primaire est initialisé et qu'il reçoit des données, il appellerait la méthode changeData qui diffuserait ensuite cela à tous les abonnés de ces données. Cela réduit le couplage de nos contrôleurs entre eux.
il suffit de le faire simple (testé avec v1.3.15):
<article ng-controller="ctrl1 as c1">
<label>Change name here:</label>
<input ng-model="c1.sData.name" />
<h1>Control 1: {{c1.sData.name}}, {{c1.sData.age}}</h1>
</article>
<article ng-controller="ctrl2 as c2">
<label>Change age here:</label>
<input ng-model="c2.sData.age" />
<h1>Control 2: {{c2.sData.name}}, {{c2.sData.age}}</h1>
</article>
<script>
var app = angular.module("MyApp", []);
var dummy = {name: "Joe", age: 25};
app.controller("ctrl1", function () {
this.sData = dummy;
});
app.controller("ctrl2", function () {
this.sData = dummy;
});
</script>