36

I'm stating to learn AngularJS, coming from a lot of different MV* frameworks. I like the framework, however I'm having trouble with passing data between Controllers.

Suppose I have a screen with some input (input.html) and a controller, let's say InputCtrl.
There's a button on this view which takes you to another screen, let's say approve (approve.html) with a controller ApproveCtrl.
This ApproveCtrl needs data from the InputCtrl. This seems like a very common scenario in bigger applications.

In my previous MV* frameworks, this would be handled like (pseudo-code):

   var self = this;
   onClick = function() {
          var approveCtrl = DI.resolve(ApproveCtrl);
          approveCtrl.property1 = self.property1;
          approveCtrl.property1 = self.property2;
          self.router.show(approveCtrl);  
   }            
  • It would work like Controller- first. You create the controller first, having a chance to put it in the right state; afterwards the View gets created.

Now, in AngularJS, I'm handling this like:

 var self = this;
 onClick = function(){
          self.$locationService.path('approve');       
 }
  • This works like View-first. You say to which view / route to navigate, the Controller gets created by the framework.

I find it hard to control the state of the created Controller and pass data to it. I've seen and tried following approaches, but all have it's own issues in my opinion:

  1. Inject a shared service into InputCtrl & ApproveCtrl and put all data to be shared on this service
    • This looks like a dirty work-around; the state in the shared service becomes global state, while I just need it to pass data to the ApproveCtrl
    • The lifetime of this shared service is way longer than what I need it for - just to pass data to the ApproveCtrl
  2. Pass the data in $routeParams
    • This gets quite messy when having the pass a lot of parameters
  3. Use $scope events
    • Conceptually, this is not something I would use events for - I just need to pass data to the ApproveCtrl, nothing event-ish
    • This is quite cumbersome; I have to send an event to the parent first, that would then broadcast it to it's children

Am I missing something here? Am I creating too many small Controllers? Am I trying to hold on to habits from other frameworks too much here?

matsjoyce
  • 5,744
  • 6
  • 31
  • 38
KoenJ
  • 1,093
  • 2
  • 13
  • 24
  • I would go with the 3rd according to your needs. Service is used to pass data between the controllers that need to share data, not states mainly. Also solution 2 is pretty much more straighforward but the route params will become a cumbersome problem as they grow. – Jimmy Kane Aug 09 '13 at 08:38
  • 3rd option is the right way. – Ye Liu Aug 09 '13 at 13:12
  • Are you going to accept XLII answer, the links were gold mines as was the diagram. – Stephen Patten Dec 10 '13 at 19:29

4 Answers4

56

In terms of structure AngularJS is more Modular than MVC one.

Classic MVC describes 3 simple layers which interact with each other in such way that Controller stitches Model with View (and Model shouldn't rather work with View directly or vice versa).

In Angular you can have multiple, some completely optional, entities which can interact between each other in multiple ways, for example:

Possible Interactions

That's why there are multiple ways of communicating your data between different entities. You can:

or

  • Send messages using AJAX backend
  • Send messages using external system (such as MQ)

...and a lot more. Due to its diversity Angular allows developer/designer to choose way they are most comfortable with and carry on. I recommend reading AngularJS Developer Guide where you can find blessed solutions to some common problems.

Community
  • 1
  • 1
XLII
  • 1,172
  • 9
  • 18
  • 2
    Thanks for your detailed answer; I know there are some options in AngularJS, I was wondering how most people deal with what I'd consider a common scenario. – KoenJ Aug 12 '13 at 17:28
  • 3
    This is a great and detailed answer, but I think using a **service** is the best option: http://stackoverflow.com/questions/20181323/passing-data-between-controllers-in-angular-js – Jess May 27 '14 at 13:54
  • 1
    That graph! I will send it to my collegues at once! – Aspelund Dec 04 '14 at 09:55
8

If your intent is to simply share data between two views, a service is probably the way to go. If you are interested in persisting to a data store, you may want to consider some sort of back-end service such as a REST API. Take a look at the $http service for this.

Clay
  • 2,932
  • 2
  • 18
  • 16
3

Even if XLII gave a complete response, I found this tutorial using a service. It's very interesting and a simple way for sharing data between controlers using the 2 ways binding property : https://egghead.io/lessons/angularjs-sharing-data-between-controllers

I still havn't used it for now.

Otherwise there is also this other way, based on events : http://www.objectpartners.com/2013/08/21/using-services-and-messages-to-share-data-between-controllers-in-angularjs/

nlko
  • 500
  • 1
  • 6
  • 9
1

If you wish to pass simple string data from one page (page1) to another page (page2), one solution is to use traditional url parameters. Invoke the page2 route url with parameter like "/page2/param1/param2". The controller of page2 will receive the parameters in "routeParams". You will be able to access parameteres as routeParams.param1 and routeParams.param2. The code below is adopted from: How to get the url parameters using angular js

Invoke the page2 route from page1's controller(js) or a url in its html with parameters as:

"/page2/param1/param2"

Page2 route:

$routeProvider.when('/page2/:param1/:param2', {
    templateUrl: 'pages/page2.html',    
    controller: 'Page2Ctrl'
});

And the controller:

.controller('Page2Ctrl', ['$scope','$routeParams', function($scope, $routeParams) {
  $scope.param1 = $routeParams.param1;
  $scope.param2 = $routeParams.param2;
  ...
}]);

Now you can access the parameters (param1 and param2) values in your page2's html/template as well.

Community
  • 1
  • 1
hadaytullah
  • 1,164
  • 13
  • 14