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.

335
demandé sur Claies 2014-02-21 01:27:13

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>

Demo: http://jsfiddle.net/27mk1n1o /

456
répondu tasseKATT 2018-05-29 08:41:31

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);
   }
});
67
répondu bennick 2016-11-10 12:55:37

il y a plusieurs façons de partager les données entre les contrôleurs

  1. à l'aide des services
  2. en utilisant $state.les services de go transit
  3. à l'aide de stateparams
  4. utilisant rootscope

explication de chaque méthode:

  1. Je ne vais pas m'expliquer comme cela a déjà été expliqué par quelqu'un

  2. utilisant $state.go

      $state.go('book.name', {Name: 'XYZ'}); 
    
      // then get parameter out of URL
      $state.params.Name;
    
  3. $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

  4. 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);
      });
    
10
répondu Ayush Mishra 2017-01-09 09:40:42

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

6
répondu Oberdan Nunes 2014-09-19 02:00:37

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

3
répondu ojus kulkarni 2017-11-18 10:10:22

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;
});
1
répondu Hinrich 2016-12-16 10:17:08

Il y a plusieurs façons de le faire.

  1. événements - déjà bien expliqué.

  2. routeur ui-expliqué ci-dessus.

  3. Service - avec la méthode de mise à jour affichée ci-dessus
  4. BAD - à L'affût des changements.
  5. 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();
        }
    }
});
1
répondu user2756335 2017-04-27 06:37:00

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.

0
répondu ewahner 2015-09-02 20:20:14

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>

-3
répondu Lumic 2015-06-01 19:22:59