web-dev-qa-db-fra.com

AngularJS: Comment puis-je passer des variables entre contrôleurs?

J'ai deux contrôleurs Angular:

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 parce que ce n'est pas défini. Cependant si j'essaye de le transmettre comme si…

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. Est-ce que quelqu'un sait comment faire ça?

Faire

Ctrl2.prototype = new Ctrl1();

Échoue également.

NOTE: Ces contrôleurs ne sont pas imbriqués l'un dans l'autre.

325
dopatraman

Une façon de partager des variables entre plusieurs contrôleurs consiste à créer un service et à l'injecter dans tout contrôleur sur lequel 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;
            }
        };
    });

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 particulièrement).

J'ai constaté que si vous souhaitez lier ces propriétés à plusieurs contrôleurs, cela fonctionnera mieux si vous liez à la propriété d'un objet plutôt qu'à 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) clarifier les choses voici un violon 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 variable de portée)
  • Liaison à des valeurs partagées mettant à jour l'interface utilisateur lors de la mise à jour des valeurs (dans myController2)
    • Liaison à une fonction qui retourne une primitive (chaîne)
    • Liaison à la propriété de l'objet
    • Liaison bidirectionnelle à la propriété d'un objet
500
Gloopy

J'aime illustrer des choses simples par des exemples simples :)

Voici un exemple très simple de 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 ici le jsbin

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;
});

Et ici le jsbin


Si c'est trop simple, voici un exemple plus sophistiqué

Aussi voir la réponse ici pour les commentaires relatifs aux meilleures pratiques

44
Dmitri Zaitsev

--- Je sais que cette réponse ne concerne pas cette question, mais je veux que les personnes qui lisent cette question et qui souhaitent gérer des services tels que des usines évitent d'avoir de la difficulté à le faire --- -

Pour cela, vous devrez utiliser un service ou une usine.

Les services sont les BEST PRACTICE pour partager des données entre des contrôleurs non imbriqués.

Une très très bonne annotation sur ce sujet à propos du partage de données concerne la façon de déclarer des objets. Je n’étais pas chanceux parce que je suis tombé dans un piège AngularJS avant de lire à ce sujet et j’étais très frustré. Alors 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 devrait ê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';
  };
});

En effet, il est recommandé (BEST PRACTICE) que le DOM (document html) contienne les appels en tant que

<div ng-model="someModel.someValue"></div>  //NOTICE THE DOT.

Ceci est très utile pour les contrôleurs imbriqués si vous souhaitez que votre contrôleur enfant puisse modifier 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 aux contrôleurs.

Disons que vous avez votre service 'Factory' et que dans l'espace de retour se trouve un objetA qui contient objectB qui contient objectC.

Si vous voulez que l’objetC se trouve dans votre oscilloscope à partir de votre contrôleur, c’est une erreur de dire:

$scope.neededObjectInController = Factory.objectA.objectB.objectC;

Cela ne fonctionnera pas ... Utilisez plutôt un seul point.

$scope.neededObjectInController = Factory.ObjectA;

Ensuite, dans le DOM, vous pouvez appeler objectC depuis objectA. C’est une pratique exemplaire liée aux usines, et la plus importante: cela aidera à éviter les erreurs inattendues et impossibles à capturer.

26
AFP_555

Solution sans créer de service, en utilisant $ rootScope:

Pour partager des propriétés entre plusieurs contrôleurs d'applications, vous pouvez utiliser Angular $ rootScope. C'est une autre option pour partager des données, en les mettant de manière à ce que les gens le sachent.

Le moyen privilégié de partager certaines fonctionnalités entre les contrôleurs est les services. Pour lire ou modifier une propriété globale, 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>
17
Sanjeev

L’échantillon ci-dessus a fonctionné comme un charme. Je viens de faire une modification au cas où je devrais gérer plusieurs valeurs. J'espère que ça aide!

app.service('sharedProperties', function () {

    var hashtable = {};

    return {
        setValue: function (key, value) {
            hashtable[key] = value;
        },
        getValue: function (key) {
            return hashtable[key];
        }
    }
});
8
Juan Zamora

J'ai tendance à utiliser des valeurs, heureux que quiconque puisse expliquer pourquoi c'est une mauvaise idée.

var myApp = angular.module('myApp', []);

myApp.value('sharedProperties', {}); //set to empty object - 

Puis injecter la valeur selon un service.

Définir 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; 

});
6
Chilledflame

J'aimerais contribuer à cette question en soulignant que la méthode recommandée pour partager des données entre contrôleurs, et même des directives, consiste à utiliser des services (usines), comme cela a déjà été souligné, mais j'aimerais également fournir une exemple de travail pratique de la façon dont cela devrait être fait.

Voici le programme de travail: http://plnkr.co/edit/Q1VdKJP2tpvqqJL1LF6?p=info

Tout d’abord, créez votre service , qui aura votre données partagées :

app.factory('SharedService', function() {
  return {
    sharedObject: {
      value: '',
      value2: ''
    }
  };
});

Ensuite, il suffit de l'injecter sur vos contrôleurs et de récupérer les données partagées sur votre scope:

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 également 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 claire pourra être utile à quelqu'un.

4
Fedaykin

L'exemple suivant montre comment passer des variables entre frères et soeurs contrôleurs et effectuer 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>
4
Zanon

Vous pouvez le faire avec des services ou des usines. Ils sont essentiellement les mêmes, à part quelques différences fondamentales. J'ai trouvé cette explication sur thinkster.io comme la plus simple à suivre. Simple, pertinent et efficace.

3
Noahdecoco

Ne pourriez-vous pas également faire de la propriété une partie du champ d'application Scopes?

$scope.$parent.property = somevalue;

Je ne dis pas que c'est juste, mais ça marche.

2
SideFX

Ah, ayez un peu de ce nouveau truc comme une autre alternative. C'est un stockage local, et fonctionne où angular fonctionne. Je vous en prie. (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édez aux valeurs:

$scope.prop1 = $localStorage.prop1;
$scope.prop2 = $localStorage.prop2;

Stocker 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.

2
kJamesy

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:

http://plnkr.co/edit/cKVsPcfs1A1Wwlud2jtO?p=preview

1
Codiee

Il y a deux façons de faire ça

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
1
Rohan Kawade

Si vous ne voulez pas faire de service, vous pouvez le faire comme ça.

var scope = angular.element("#another ctrl scope element id.").scope();
scope.plean_assign = some_value;
0
thanksnote