0

I understand that using $rootScope to share values between controllers is a bad idea and everybody recommends using Services and as an answer links to the the angular docs. However I am at loss there, because the official documentation does not show any simple example, and when I tried to implement some examples from here, StackOverflow – they did not work for me (maybe because I am using ng-repeat?). I have been trying to solve it for several days, as to not to bother you here, but now I am at totally at loss.

Could you please show me how to solve the example below, and I will then use it in my application (where I have about 50 different scopes used in 5 different controllers). The example below is the simple outline of my problem. I have also created a plunker for it http://plnkr.co/edit/J4fZ51koueyUX9mXqzDk?p=preview

I have three controllers in my JS:

app.controller('TotalCalc', function($scope) {

  });

app.controller('color', function($scope) {
  $scope.colors = [
  {name1: "Red",price1: 300},
  {name1: "Green",price1: 660},
  {name1: "Black",price1: 920}
];});

app.controller('coating', function($scope) {
  $scope.coatings = [
  {name2: "Single coating",price2: 2},
  {name2: "Double coatings",price2: 4},
  {name2: "Triple coating",price2: 7}
];});

And in my HTML I have:

<div class="container" ng-controller="TotalCalc">
Here I want to calculate a value: (color selected price) * (coating multiplier)<br>
Using the "selected.price1" * "selected.price2", from the "color" and "coating" controllers below.

<div class="col-xs-6" ng-controller="color">
<strong>Color selected price: {{selected.price1 ||0}}</strong>
 <div class="list-group small">
  <a ng-repeat="color in colors" ng-click="$parent.selected = color" class="list-group-item" ng-class="{active:selected==color}"><span class="badge pull-right">$ {{color.price1}}</span>{{color.name1}}</a>
 </div>
</div>

<div class="col-xs-6" ng-controller="coating">
 <strong>Coating multiplier: {{selected.price2 ||0}}</strong>
 <div class="list-group small">
  <a ng-repeat="coating in coatings" ng-click="$parent.selected = coating" class="list-group-item" ng-class="{active:selected==coating}"><span class="badge pull-right">{{coating.price2}}</span>{{coating.name2}}</a>
 </div>
</div>
</div>

See, that whole place (single-page-application) is under the "TotalCalc" controller and from there I cannot access the values from the other two controllers inside it.

I understand that I should use the Service(?) somehow, if I want to access any values/scopes from the different controllers throughout the whole application. But after several days reading up and trying, I cannnot find a way for it to work. :( Can you please use my simplified example above, and to show me how it is done? Thank you in advance.

2
  • Why use different controllers? Commented Dec 25, 2013 at 16:37
  • @Neikos Because I could not use different ng-repeat in one controller, and when I was chosing from one list, and then wanted to choose from another list, the selection from the first list got cancelled. That is why I put them in different controllers. But you gave me an idea, I will try it again, since I have different names for the values... EDIT: I have tried with different names, but no, it is still using all the lists in one controller as one big list, I cannot separate them. That's why I had to put them in separate controllers. Commented Dec 25, 2013 at 17:30

1 Answer 1

1

As @Nikos pointed out, you really don't need multiple nested controllers here. That being said, here is an example of using a service as well as some custom events for communicating. The events aren't needed as you can bind all the data together through the service , but I put them in for inspiration

app.factory('CoatingService', function() {
  var thisService = {
    colors: [
      {name1: "Red",price1: 300},
      {name1: "Green",price1: 660},
      {name1: "Black",price1: 920}
    ],
    coatings: [
      {name2: "Single coating",price2: 2},
      {name2: "Double coatings",price2: 4},
      {name2: "Triple coating",price2: 7}
    ],

    selected:{
      color:{},
      coating:{}
    }
  }

  return thisService

})

app.controller('TotalCalc', function($scope, CoatingService) {
  $scope.selected=CoatingService.selected;
 function updateTotal(){
      $scope.totalprice= ($scope.selected.color.price1 ||0) + ($scope.selected.coating.price2||0)
 }
 updateTotal();

 $scope.$on('doPriceUpdate',function(){
   updateTotal();
  })

});

app.controller('color', function($scope, CoatingService) {

  $scope.colors = CoatingService.colors;
  $scope.selected = CoatingService.selected;

  $scope.updateColor=function(color){
    $scope.selected.color=color;
    $scope.$emit('doPriceUpdate')
  }  

});
/* similar pattern for coating controller*/

You could do this all within one controller though quite easily with less code but still keep the service to store data

DEMO

Sign up to request clarification or add additional context in comments.

5 Comments

It works! Thank you! Now I will have to understand it and implement in my application. However, you and @Neikos have touched the subject of using multiple lists and values in one controller. That would be the best solution for me, but I had to reject it several days ago, because I could not create several separate ng-repeat'ed lists. See plnkr.co/edit/3kGyGhKk9wdwqesMyY5q?p=preview on the top, I have two lists, but when I choose one value, the other cancels. Do you know how to solve this? In that case it would be much easier for my app. Thank you again.
Here's that same demo you just sent, turned into one controller including price calc. Very little modification required. Also standardized name and price in data plnkr.co/edit/XvJEZLsZHdGGFnsdmXFe?p=preview
Wow, that is much better alternative to Services, in my case. I will implement this, and parallel to that, I will also try to understand the services you have kindly described to me before.
the main concept you need to understand from the services demo is that objects are shared by reference. var a={}, b=a. Anything you do to property in b or a will do same in other...they are references to the exact same object. Must understand this concept working with angular, it is built on leveraging that inheritance
conversely..need to understand ramifications of nesting scopes also. Best to use new controllers for non related functionality, in this case all 3 are closely related

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.