[ACCEPTED]-AngularJS: How can I pass variables between controllers?-angularjs-controller

Accepted answer
Score: 508

One way to share variables across multiple 11 controllers is to create a service and inject it in any 10 controller where you want to use it.

Simple service example:

angular.module('myApp', [])
    .service('sharedProperties', function () {
        var property = 'First';

        return {
            getProperty: function () {
                return property;
            },
            setProperty: function(value) {
                property = value;
            }
        };
    });

Using the service in a controller:

function Ctrl2($scope, sharedProperties) {
    $scope.prop2 = "Second";
    $scope.both = sharedProperties.getProperty() + $scope.prop2;
}

This 9 is described very nicely in this blog (Lesson 2 and 8 on in particular).

I've found that if you 7 want to bind to these properties across 6 multiple controllers it works better if 5 you bind to an object's property instead 4 of a primitive type (boolean, string, number) to 3 retain the bound reference.

Example: var property = { Property1: 'First' }; instead 2 of var property = 'First';.


UPDATE: To (hopefully) make things more clear 1 here is a fiddle that shows an example of:

  • Binding to static copies of the shared value (in myController1)
    • Binding to a primitive (string)
    • Binding to an object's property (saved to a scope variable)
  • Binding to shared values that update the UI as the values are updated (in myController2)
    • Binding to a function that returns a primitive (string)
    • Binding to the object's property
    • Two way binding to an object's property
Score: 45

I like to illustrate simple things by simple 3 examples :)

Here is a very simple Service example:


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

And 2 here the jsbin

And here is a very simple Factory example:


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

And here the jsbin


If 1 that is too simple, here is a more sophisticated example

Also see the answer here for related best practices comments

Score: 26

--- I know this answer is not for this question, but I want people who reads this question and want to handle Services such as Factories to avoid trouble doing this ----

For this you will need to use a Service 26 or a Factory.

The services are the BEST PRACTICE to share 25 data between not nested controllers.

A very 24 very good annotation on this topic about 23 data sharing is how to declare objects. I 22 was unlucky because I fell in a AngularJS 21 trap before I read about it, and I was very 20 frustrated. So let me help you avoid this 19 trouble.

I read from the "ng-book: The complete 18 book on AngularJS" that AngularJS ng-models 17 that are created in controllers as bare-data 16 are WRONG!

A $scope element should be created 15 like this:

angular.module('myApp', [])
.controller('SomeCtrl', function($scope) {
  // best practice, always use a model
  $scope.someModel = {
    someValue: 'hello computer'
  });

And not like this:

angular.module('myApp', [])
.controller('SomeCtrl', function($scope) {
  // anti-pattern, bare value
  $scope.someBareValue = 'hello computer';
  };
});

This is because 14 it is recomended(BEST PRACTICE) for the 13 DOM(html document) to contain the calls 12 as

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

This is very helpful for nested controllers 11 if you want your child controller to be 10 able to change an object from the parent 9 controller....

But in your case you don't want nested scopes, but there is a similar aspect to get objects from services to the controllers.

Lets say you have your service 8 'Factory' and in the return space there 7 is an objectA that contains objectB that 6 contains objectC.

If from your controller 5 you want to GET the objectC into your scope, is 4 a mistake to say:

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

That wont work... Instead use only one dot.

$scope.neededObjectInController = Factory.ObjectA;

Then, in 3 the DOM you can call objectC from objectA. This 2 is a best practice related to factories, and 1 most important, it will help to avoid unexpected and non-catchable errors.

Score: 17

Solution without creating Service, using $rootScope:

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

The preferred 4 way to share some functionality across Controllers 3 is Services, to read or change a global 2 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 1 in a template (Access properties with $root):

<div ng-controller="Ctrl1">
    <div class="banner" ng-show="$root.showBanner"> </div>
</div>
Score: 9

The sample above worked like a charm. I 2 just did a modification just in case I need 1 to manage multiple values. I hope this helps!

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

    var hashtable = {};

    return {
        setValue: function (key, value) {
            hashtable[key] = value;
        },
        getValue: function (key) {
            return hashtable[key];
        }
    }
});
Score: 6

I tend to use values, happy for anyone to 3 discuss why this is a bad idea..

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

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

Then inject 2 the value as per a service.

Set in ctrl1:

myApp.controller('ctrl1', function DemoController(sharedProperties) {
  sharedProperties.carModel = "Galaxy";
  sharedProperties.carMake = "Ford";
});

and 1 access from ctrl2:

myApp.controller('ctrl2', function DemoController(sharedProperties) {
  this.car = sharedProperties.carModel + sharedProperties.carMake; 

});
Score: 5

The following example shows how to pass 4 variables between siblings controllers and take an 3 action when the value changes.

Use case 2 example: you have a filter in a sidebar 1 that changes the content of another view.

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>
Score: 4

I'd like to contribute to this question 11 by pointing out that the recommended way 10 to share data between controllers, and even 9 directives, is by using services (factories) as 8 it has been already pointed out, but also 7 I'd like to provide a working practical 6 example of how to that should be done.

Here is the working plunker: http://plnkr.co/edit/Q1VdKJP2tpvqqJL1LF6m?p=info

First, create your 5 service, that will have your shared data:

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

Then, simply inject 4 it on your controllers and grab the shared data on 3 your 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;
});

You can also do that for your 2 directives, it works the same way:

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

Hope this practical 1 and clean answer can be helpful to someone.

Score: 3

You could do that with services or factories. They 4 are essentially the same apart for some 3 core differences. I found this explanation 2 on thinkster.io to be the easiest to follow. Simple, to 1 the point and effective.

Score: 2

Couldn't you also make the property part 2 of the scopes parent?

$scope.$parent.property = somevalue;

I'm not saying it's 1 right but it works.

Score: 2

Ah, have a bit of this new stuff as another 6 alternative. It's localstorage, and works 5 where angular works. You're welcome. (But 4 really, thank the guy)

https://github.com/gsklee/ngStorage

Define your defaults:

$scope.$storage = $localStorage.$default({
    prop1: 'First',
    prop2: 'Second'
});

Access 3 the values:

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

Store the values

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

Remember to inject 2 ngStorage in your app and $localStorage 1 in your controller.

Score: 2

There are two ways to do this

1) Use get/set 1 service

2) $scope.$emit('key', {data: value}); //to set the value

 $rootScope.$on('key', function (event, data) {}); // to get the value
Score: 2

Second Approach :

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>

For more details 1 see plunker :

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

Score: 2

I looked thru the answers above, I recommend 6 pejman's Dec 29 '16 at 13:31 suggestion 5 but he/she has not left a full answer. Here 4 it is, I will put this as --> (you need 3 a service and a listener $watch on one of the 2 scopes from controllers for changes in the 1 service area)

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

app.service('bridgeService', function () {
    var msg = ""; 
    return msg;
});
app.controller('CTRL_1'
, function ($scope, $http, bridgeService) 
{
    $http.get(_restApi, config)
    .success(
    function (serverdata, status, config) {
        $scope.scope1Box = bridgeService.msg = serverdata;
    });
});
app.controller('CTRL_2'
, function ($scope, $http, bridgeService) 
{
    $scope.$watch( function () {
        return (bridgeService.msg);
    }, function (newVal, oldVal) {
        $scope.scope2Box = newVal;
    }, true
    );
});
Score: 0

If you don't want to make service then you 1 can do like this.

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

More Related questions