Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have a basic controller that displays my products,

App.controller('ProductCtrl',function($scope,$productFactory){
     $productFactory.get().success(function(data){
           $scope.products = data;
     });
});

In my view I'm displaying this products in a list

<ul>
    <li ng-repeat="product as products">
        {{product.name}}
    </li>
</ul

What I'm trying to do is when someone click on the product name, i have another view named cart where this product is added.

 <ul class="cart">
      <li>
          //click one added here
      </li>
      <li>
          //click two added here
      </li>
 </ul>

So my doubt here is, how do pass this clicked products from first controller to second? i assumed that cart should be a controller too.

I handle click event using directive. Also i feel i should be using service to achieve above functionality just can't figure how? because cart will be predefined number of products added could be 5/10 depending on which page user is. So i would like to keep this generic.

Update:

I created a service to broadcast and in the second controller i receive it. Now the query is how do i update dom? Since my list to drop product is pretty hardcoded.

share|improve this question

4 Answers 4

up vote 38 down vote accepted

From the description, seems as though you could be using a service. Check out http://egghead.io/lessons/angularjs-sharing-data-between-controllers and AngularJS Service Passing Data Between Controllers to see some examples.

You could define your product service as such:

app.service('productService', function() {
  var productList = [];

  var addProduct = function(newObj) {
      productList.push(newObj);
  }

  var getProducts = function(){
      return productList;
  }

  return {
    addProduct: addProduct,
    getProducts: getProducts
  };

});

Dependency inject the service into both controllers.

In your ProductController, define some action that adds the selected object to the array:

app.controller('ProductController', function($scope, productService) {
    callToAddToProductList = function(currObj){
        productService.addProduct(currObj);
    };
});

In your CartController, get the products from the service:

app.controller('CartController', function($scope, productService) {
    $scope.products = productService.getProducts();
});
share|improve this answer
    
Cart controller will update once when getProducts() is called? Or every time new product is added? –  kishanio Nov 24 '13 at 22:02
    
If you want it to automatically update, you can add the broadcast from Maxim Shoustin's answer and call getProducts() within the $on function to update the CartCtrl's scope. –  Charx Nov 24 '13 at 22:21
    
In order to get this set up to work for me, I needed to add a return to the app.service('productService', function() { }); in order to expose those properties and methods so they could be used in the other controllers. –  krillgar Jun 6 at 15:44
2  
@krillgar You are completely correct, that was overlooked initially. I've edited the answer to reflect a working solution. –  Charx Jun 6 at 19:27
    
I have posted a solution below to create global variables without creating Service, but instead using $rootScope. –  Sanjeev Aug 30 at 15:25

how do pass this clicked products from first controller to second?

On click you can call method that invokes broadcast:

$rootScope.$broadcast('SOME_TAG', 'your value');

and the second controller will listen on this tag like:

$scope.$on('SOME_TAG', function(response) {
      // ....
})

Since we can't inject $scope into services, there is nothing like a singleton $scope.

But we can inject $rootScope. So if you storing value into Service, you can run $rootScope.$broadcast('SOME_TAG', 'your value'); in the Service body. (See @Charx description about services)

app.service('productService',  function($rootScope) {/*....*/}
share|improve this answer
1  
Yup this works like charm I'm using factory? There is just one last thing where I'm stuck i do get data in new controller every time i click product. Now how do i update it in DOM? Because i already have lets say list of 5 hardcoded with borders so each products need to go inside them –  kishanio Nov 24 '13 at 22:47
    
@KT - Did you ever get an answer? It seems like an obvious question but I can't find the answer anywhere. I want a controller to change some value. When that app value changes then any other listening controllers should update themselves as necessary. Can't find it. –  daylight Feb 28 at 18:52
1  
@daylight the answer on your q. is based on what controller structure you have: parallel or child-parent. $rootScope.$broadcast notifies all controllers that have parallel structure aka the same level. –  Maxim Shoustin Feb 28 at 19:33
    
@MS Thanks for the reply. Is there a way to do this using $watch? BTW, Mine are parallel controllers and I got it to work using your method. For me, whenever I try to add the $watch (even to $rootScope) the method associated with the $watch in the 2nd controller would only fire the first time (initialization of the 2nd controller). Thanks. –  daylight Feb 28 at 20:34
1  
we can use $watch if the value exists on $rootScope level. Otherwise only broadcast might notify other controllers. FYI, if other programmer sees in your code broadcast - the logic is clear what you try to do - "broadcast event". Anyways, from my exp. its not good practice to use rootscope for watch. About "fire 1st time only": take a look on this example: plnkr.co/edit/5zqkj7iYloeHYkzK1Prt?p=preview you have old and new values. be sure that each time you get new value that doesnt equal to old one –  Maxim Shoustin Feb 28 at 22:32

Solution without creating Service, using $rootScope:

To share properties across app Controllers you can use Angular $rootScope. This is another option to share data, putting it so that people know about it.

The preferred way to share some functionality across Controllers is Services, to read or change a global property you can use $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;
}]);

Using $rootScope in a template (Access properties with $root):

<div ng-controller="Ctrl1">
    <div class="banner" ng-show="$root.showBanner"> </div>
</div>
share|improve this answer
1  
$rootScope should be avoided as much as possible. –  Shaz Sep 10 at 15:09
    
@Shaz could you elaborate why? –  Mirko Sep 11 at 14:17
    
@Mirko You should try to avoid global state as much as you can because anyone can change it -making your program state unpredictable. –  Umut Seven Sep 12 at 12:36
    
There are two ways to share data between controllers: 1) Factories/Services 2) $rootScope - All other scopes are descendant scopes of the root scope. The preferred way to share some functionality across Controllers is Services, to read or change a global property you can use $rootscope. I added this so that people know about its usage in controller/views. This is a feature provided by angular and i have not read anywhere that we should not use it, you have to decide as per your case. For me this was the best option and it worked pretty well. –  Sanjeev Sep 15 at 5:26

I've created a factory that controls shared scope between route path's pattern, so you can maintain the shared data just when users are navigating in the same route parent path.

.controller('CadastroController', ['$scope', 'RouteSharedScope',
    function($scope, routeSharedScope) {
      var customerScope = routeSharedScope.scopeFor('/Customer');
      //var indexScope = routeSharedScope.scopeFor('/');
    }
 ])

So, if the user goes to another route path, for example '/Support', the shared data for path '/Customer' will be automatically destroyed. But, if instead of this the user goes to 'child' paths, like '/Customer/1' or '/Customer/list' the the scope won't be destroyed.

You can see an sample here: http://plnkr.co/edit/OL8of9

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.