[ACCEPTED]-AngularJS: How can I pass variables between controllers?-angularjs-controller
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
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
--- 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.
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>
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];
}
}
});
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;
});
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>
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.
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.
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.
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.
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
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 :
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
);
});
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
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.