I set a $rootScope variable in one of my modules and now want to access that same $rootScope variable in another module. Thus far I can see that in both modules the variable has been set properly, but when I try accessing the variable in $rootScope, I only get undefined.
How can I access this variable without doing a factory/service workaround? The variable is really simple and $rootScope should suffice for what I need. I've put some generic sample code below to illustrate the issue:
file1.js
var app = angular.module('MyApp1', []);
app.controller('Ctrl1', ['$scope', '$rootScope', function($scope, $rootScope) {
$scope.myFunc = function() {
$rootScope.test = 1;
}
}
file2.js
var app = angular.module('MyApp2', []);
app.controller('Ctrl2', ['$scope', '$rootScope', function($scope, $rootScope) {
$scope.need_to_access_this = $rootScope.test; // undefined
console.log($rootScope); // returns JS object w/ test property set to 1
}
I was just stuck in the same problem when I figured out that you have define those properties for $rootScope before the controllers or services load. So what I did was set inital values when the application runs. In your case it will be like:
app.run(function($rootScope){
$rootScope.test="variable";
})
`
In Ctrl1 the $rootScope.test value is set inside the $scope.myFunc.
The problem is that you aren't calling that function, so the test property in $rootScope is never set.
You need to call $scope.myFunc(); in Ctrl1 or set $rootScope.test = 1; dirrectly in the Controller:
app.controller('Ctrl1', ['$scope', '$rootScope', function($scope, $rootScope) {
$scope.myFunc = function() {
$rootScope.test = 1;
};
$scope.myFunc();
}
or
app.controller('Ctrl1', ['$scope', '$rootScope', function($scope, $rootScope) {
$rootScope.test = 1;
}
EDIT:
The above suggestions still remain valid, thus you need to call myFunc().
But the problem with your code is that Ctrl1 belongs to MyApp1 and Ctrl2 belongs to MyApp2.
Every application has a single root scope (docs here)
You will need to create Ctrl2 as a controller of MyApp1:
angular.module('MyApp1')
.controller('Ctrl2', ['$scope', '$rootScope', function($scope, $rootScope) {
$scope.need_to_access_this = $rootScope.test; // undefined
console.log($rootScope); // returns JS object w/ test property set to 1
}]);
Related
I am trying to share a variable between a controller and a function. But i get an error from the controller, saying this:
TypeError: Cannot read property 'getSet' of undefined
I have gone through numerous tutorials, but don't know where am I going wrong.
My service code is like this:
app.service('shareData', function() {
var selected = ["plz", "print", "something"];
var putSet = function(set) {
selected = set;
};
var getSet = function() {
return selected;
};
return {
putSet: putSet,
getSet: getSet
};
});
I am able to reach selected from my function defined like this:
setDisplay = function($scope, $mdDialog, shareData) {
console.log(shareData.getSet()); // this is working
$scope.selected = shareData.getSet();
$scope.hide = function() {
$mdDialog.hide();
};
$scope.cancel = function() {
$mdDialog.cancel();
};
$scope.answer = function(answer) {
$mdDialog.hide(answer);
};
};
My controller is like this:
app.controller('topicController', ['$scope', '$http', '$mdDialog', 'shareData',
function ($scope, $http, $mdDialog, $mdToast, shareData) {
console.log(shareData.getSet()); // NOT WORKING
}]);
You had extra $mdToast in your topicController controller's factory function, you need to remove it.
The reason behind it was not working is, currently you had 4 dependency mentioned in array like ['$scope', '$http', '$mdDialog', 'shareData', function & then you are using its instance inside the function next to DI array. Inside that function you had actually 5 dependencies where $mdToast extra. So behind the scene what happening is $scope of function hold an value of '$scope' DI array likewise you go right to left. But when it comes to $mdToast(in controller function) it was holding a value of 'shareData'(of DI array) & then the next parameter shareData get nothing.
app.controller('topicController', ['$scope', '$http', '$mdDialog', 'shareData',
function ($scope, $http, $mdDialog, shareData) { //<--removed $mdToast
console.log(shareData.getSet());
}
]);
NOTE: You are using DI inline array annotation, so the sequence in which dependency are injected in array, in same sequence you should
inject then in underlying factory function.
I have a controller:
appControllers.controller('MeetingListController', ['$scope', '$route', '$location', function($scope, $route, $location){
console.log($scope.go);
$scope.progressRun = function($event){
$scope.go = true;
};
});
I don't undersand because when go variable changes value in progressRun function,
console.log doesn't show right value and it called before and after progressRun function.
Simply move your console.log() after you change the go variable in the progressRun() function...:
appControllers.controller('MeetingListController', ['$scope', '$route', '$location', function($scope, $route, $location) {
$scope.go = 'initial value you want to assign to this variable';
$scope.progressRun = function($event) {
$scope.go = true;
console.log($scope.go);
};
}]);
UPDATE:
If you want to log the variable value anytime it changes (even when it's value should be changed outside progressRun() function, use:
$scope.$watch('go', function() {
console.log($scope.go);
});
Just after go variable initialization (as correctly #Shreevardhan suggestes).
Either log the value after changing
$scope.go = true;
console.log($scope.go);
Or, use $watch on the variable
$scope.$watch('go', function() {
console.log($scope.go);
});
PS: $watch will log each time the value changes.
I dont understand what I am missing
I dont get result on html i think this problem managing with controllerAs syntax
note: I can see the result in console console.log(this.movie); - its from controller
app.js
var app = angular.module('mfApp',['ngRoute', 'appControllers']);
app.config(function($routeProvider){
$routeProvider.
when('/:detail',{
templateUrl: 'template/detail.html',
controller : 'detailCtrl' ,
controllerAs: 'movieAs'
}).otherwise({
redirectTo: '/'
});
});
controller.js
var mfControllers = angular.module('appControllers', []);
mfControllers.controller('detailCtrl', ['$scope', '$routeParams', 'appServices', function($scope, $routeParams, appServices){
this.movie = [];
this.id = $routeParams.detail;
appServices.homeSearch(this.id).success(function(response){
this.movie = response;
console.log(this.movie);
// Yes, I do get array result in console
});
}]);
html - template/detail.html
My try
{{movieAs.Title}}
{{movieAs.movie.Title}}
{{movie.movieAs.Title}}
{{movie.Title}} {{title}}
mfControllers.controller('detailCtrl', ['$scope', '$routeParams', 'appServices', function($scope, $routeParams, appServices){
var me = this;
me.movie = [];
me.id = $routeParams.detail;
appServices.homeSearch(me.id).success(function(response){
me.movie = response;
console.log(me.movie);
// Yes, I do get array result in console
});
}]);
EDIT
In Javascript functions are stored as objects, so from your callbeck method inside succeess, you call this which refers to the method that you are running and not to the controller scope.
It is best practice to store the reference to the controller in a variable which can be accessed by the callback methods. me is quite an arbitrary name but widely used to refer as the parent caller. https://github.com/johnpapa/angular-styleguide
The problem is due to wrong this reference.
var mfControllers = angular.module('appControllers', []);
mfControllers
.controller('detailCtrl', ['$scope', '$routeParams', 'appServices', function($scope, $routeParams, appServices) {
var vm = this;
vm.movie = [];
vm.id = $routeParams.detail;
appServices
.homeSearch(vm.id)
.success(function(response) {
// vm !== this; here
vm.movie = response;
console.log(vm.movie);
});
}]);
A good practice when using controllerAs syntax is to assign this to vm at the very beginning of a controller. It holds the reference of the controller correctly.
That is necessary because of javascript function scoping. It will be long to explain it here, but the gist of it is that function creates a new scope, this inside a function will be different. Todd Mott has a very great write up on this.
Take the following plunk as an example:
http://plnkr.co/edit/vKFevXhhSprzFvesc6bG?p=preview
var app = angular.module('plunker', []);
app.service('SomeService', ['$rootScope', function ($rootScope) {
var service = {
value: false
}
return service;
}]);
app.controller('MainCtrl', ['$scope', 'SomeService', function($scope, SomeService) {
$scope.value = SomeService.value;
//$scope.$watch(function () { return SomeService.value; }, function (data) { $scope.value = data; });
}]);
app.controller('SecondaryCtrl', ['$scope', 'SomeService', function($scope, SomeService) {
$scope.toggleValue = function () {
SomeService.value = !SomeService.value;
}
}]);
2 controllers and a service, 1 controller (SecondaryCtrl) updates a property on the service and the other controller (MainCtrl) references this property and displays it.
Note the $watch expression commented out in MainCtrl - with this line uncommented, everything works as expected but my question - is it necessary? Shouldn't the watch be implicit or am I doing something wrong?
When you assign the value of SomeService.value to your scope variable, you are creating a copy of the variable which is a distinct object from the value inside SomeService. By adding the watch expression you were simply keeping the two variables (the one in the scope and the one in SomeService) synchronised.
The easiest way to go about this is not to copy the value, but create a reference to the service itself. So in MainCtrl
$scope.someService = SomeService;
and in your html
Value: {{someService.value}}
this way you are actually binding to the value inside SomeService.
I'm using angular js and have got a controller looking like this
myApp = angular.module("myApp.controllers", []);
myApp.controller("ScheduleCtrl", function($scope, $http, ScheduleService){
$scope.hours = 4;
ScheduleService.test();
ScheduleService.initializeSchedule();
});
and a service (in another file) looking like this
myApp = angular.module('myApp.services', []);
myApp.factory('ScheduleService', ['$rootScope', function($rootScope){
return {
test :
function(){
alert("Test");
},
initializeSchedule :
function(){
alert($rootScope.hours);
}
};
});
To assure everyone that things are hooked up properly from service to controller, the first call to "test()" inside my controller produces the desired output in the alert box. However, for the next function, which as of now should be alerting "4", is instead alerting "undefined".
How can I use either $rootScope or something else in order to utilize scope variables to my service.
You need to inject $rootScope into your controller and use $rootScope instead of $scope. DEMO
myApp.controller("ScheduleCtrl", function($scope, $rootScope, $http, ScheduleService){
$rootScope.hours = 4;
ScheduleService.test();
ScheduleService.initializeSchedule();
});
But in this case you don't need to use $rootScope. You can just pass data as parameter into service function.
return {
test :
function(){
alert("Test");
},
initializeSchedule :
function(hours){
alert(hours);
}
};
How to use Angular $rootScope in your controller and view
To share global properties across app Controllers you can use Angular $rootScope. This is another option to share data.
The preferred way to share common functionality across Controllers is Services, to read or change a global property you can use $rootscope.
All other scopes are descendant scopes of the root scope, so use $rootScope wisely.
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>
The problem is that $scope is an isolated scope created for your controller. You need to inject the $rootScope into your controller and modify hours on that if you want it to show up in your service.
See more about scope hierarchies here.
controller:
angular.module('myApp', []).controller('ExampleController', ['$scope', '$rootScope', 'ScheduleService', function($scope, $rootScope, ScheduleService) {
$scope.hours = 4;
$rootScope.hours = 42;
ScheduleService.test();
ScheduleService.initializeSchedule();
}]);
service:
angular.module('myApp')
.factory('ScheduleService', function($rootScope) {
return {
test :
function(){
alert("Test");
},
initializeSchedule :
function(childScopeHours){
alert($rootScope.hours);
}
};
});
Working plnkr.