I have variable called "name" in the $scope namespace($scope.name).
I modify this variable from different controllers and from different modules. The code is provided below:
var myApp = angular.module('myApp',['myModule', 'anotherModule']);
var myModule = angular.module('myModule', []);
myModule.controller( 'MyCtrl', [ '$scope', function($scope) {
$scope.name = 'Superhero';
console.log("My module");
} ]);
myModule.controller( 'MyCtrl2', [ '$scope', function($scope){
$scope.name = 'Another hero';
}]);
var anotherModule = angular.module('anotherModule', []);
anotherModule.controller( 'AnotherCtrl', [ '$scope', function($scope){
$scope.name = 'Hero';
console.log("Another Module");
}]);
I expect all of the variables to be synced to the same variable. However, each "name" variable has different values at different controllers.
Why? and how can I make all those same variables to be synced?
Here is the JSFiddle: http://jsfiddle.net/yaprak/3Bc7f/1/
It's because they reside in different scopes. To sync $scope.name to the same value, you need to create a service that holds the value.
By default, controllers can't share data, but controllers and services can.
Update
I updated your fiddle
http://jsfiddle.net/3Bc7f/6/
var myApp = angular.module('myApp',['myModule', 'anotherModule']);
var myModule = angular.module('myModule', ['myFactory']);
myModule.controller( 'MyCtrl', [ '$scope', 'data', function($scope, data) {
$scope.name = data.name;
console.log(data.name);
} ]);
myModule.controller( 'MyCtrl2', [ '$scope', 'data', function($scope, data) {
$scope.name = data.name;
console.log(data.name);
}]);
var anotherModule = angular.module('anotherModule', []);
anotherModule.controller( 'AnotherCtrl', [ '$scope', 'data', function($scope, data) {
$scope.name = data.name;
console.log(data.name);
}]);
angular.module('myFactory', [])
.factory('data',[ function() {
return {
'name': 'John Doe'
};
}])
;
You should use service with two way binding data
var storage = { name : 'Tolya'}
myApp.service('srv', function() {
return storage;
})
http://jsfiddle.net/molo4nik11/3Bc7f/2/
You can use $rootScope instead of $scope. Now all scope of name have hero.
var myApp = angular.module('myApp',['myModule', 'anotherModule']);
var myModule = angular.module('myModule', []);
myModule.controller( 'MyCtrl', [ '$rootScope', function($rootScope) {
$rootScope.name = 'Superhero';
console.log("My module");
} ]);
myModule.controller( 'MyCtrl2', [ '$rootScope', function($rootScope){
$rootScope.name = 'Another hero';
}]);
var anotherModule = angular.module('anotherModule', []);
anotherModule.controller( 'AnotherCtrl', [ '$rootScope', function($rootScope){
$rootScope.name = 'Hero';
console.log("Another Module");
}]);
Related
angular.module('app').controller('ConvertController', ['$rootScope', '$scope', '$http', '$state', 'toaster', 'StorageManager', function($rootScope, $scope, $http, $state, toaster, StorageManager) {
$scope.authError = null;
$scope.init = function() {
var _authManager = window.client.getAuthManager();
};
$scope.init();
$scope.refreshDataForList = function() {
$scope.list = userlist.get();
};
$scope.searchConversation = function() {
var data = {
searchText: $scope.searchText
};
};
$scope.onchange = function(presence) {
console.log("IN CONTROLLER");
};
}])
I am using karma-jasmine to test my angular app. But while doing testing I am facing problem to access getAuthManager(). It gives error "cannot read getAuthManager() of undefined". However I have included all the files in proper order.
My app.js, service.js, controller.js are declared as below. My problem is the controller only pickup the initial values {userId: -1, networkName: 'xyz'} set in the service.js, even though the values are changed to { userId: 129, networkName: 'mydomainaccoutname' } in myApp.run() block in the app.js. I have correctly injected the value provider to myApp.run() as well as the controller. How do I get the controller to pick up the updated values? Thanks.
app.js
(function () {
'use strict';
//debugger;
var myApp = angular.module('myApp', [
// Angular modules
'ngAnimate', // animations
//'ngRoute', // routing
'ngSanitize', // sanitizes html bindings (ex: sidebar.js)
'ui.router', // state routing
'ui.grid',
'ui.grid.pagination',
'ngResource', // RESTful resource
// Custom modules
'common', // common functions, logger, spinner
'common.bootstrap', // bootstrap dialog wrapper functions
// 3rd Party Modules
'ui.bootstrap' // ui-bootstrap (ex: carousel, pagination, dialog)
]);
myApp.run(['$templateCache', '$rootScope', '$state', '$stateParams', 'currentUserAccount', 'userFactory',
function ($templateCache, $rootScope, $state, $stateParams, currentUserAccount, userFactory) {
//currentUserAccount is a value provider service
currentUserAccount = { userId: 129, networkName: 'mydomainaccoutname' };
}]);
})();
service.js
'use strict';
angular.module('myApp')
.value('version', '5.0')
.value('currentUserAccount', {
userId: -1,
networkName: 'xyz'
});
controller.js
(function () {
'use strict';
//debugger;
var controllerId = 'shellCtrl';
angular.module('cmtApp').controller(controllerId,
['$rootScope', 'common', 'config', 'currentUserAccount', shell]);
function shell($rootScope, common, config, currentUserAccount) {
var vm = this;
var logSuccess = common.logger.getLogFn(controllerId, 'success');
var events = config.events;
vm.busyMessage = 'Please wait ...';
vm.isBusy = true;
vm.isAdmin = false;
vm.currentUser = currentUserAccount;
vm.spinnerOptions = {
radius: 40,
lines: 7,
length: 0,
width: 30,
speed: 1.7,
corners: 1.0,
trail: 100,
color: '#F58A00'
};
activate();
function activate() {
logSuccess('CMT loaded!', null, true);
common.activateController([], controllerId);
}
};
})();
Why not use a actual service instead? You can have your service like follows.
angular.module('app')
.service('UserService', [function() {
var currentUser = {
userId: -1,
networkName: 'xyz'
};
var getCurrentUser = function() {
return currentUser;
};
var setCurrentUser = function(user) {
currentUser = user;
};
// public functions
return {
getCurrentUser: getCurrentUser,
setCurrentUser: setCurrentUser
};
}]);
Then in your controller, you can do something like this:
(function () {
'use strict';
//debugger;
var controllerId = 'shellCtrl';
angular.module('cmtApp').controller(controllerId,
['$rootScope', 'common', 'config', 'UserService', shell]);
function shell($rootScope, common, config, UserService) {
var vm = this;
....
vm.currentUser = UserService.getCurrentUser();
...
};
})();
Then in your app runner:
myApp.run(['$templateCache', '$rootScope', '$state', '$stateParams', 'UserService', 'userFactory',
function ($templateCache, $rootScope, $state, $stateParams, currentUserAccount, userFactory) {
//currentUserAccount is a value provider service
UserService.setCurrentUser({ userId: 129, networkName: 'mydomainaccoutname' });
}]);
I'm running a tutorial however they are using a version of AngularJS before 1.3.8.
What am I missing with my code so this data service can be injected?
They are using the following code to inject a service into a controller:
var myApp = angular.module('myApp', []);
myApp.factory('Data', function () {
return { message: "I'm data from a service" };
});
function FirstCtrl($scope, Data) {
$scope.data = Data;
}
function SecondCtrl($scope, Data) {
$scope.data = Data;
}
Here is my code I am trying to alter so it works:
var myApp = angular.module('app', []);
myApp.factory('Data', function(){
return {message:"Data from service"}
});
angular.module('app', Data)
.controller('FirstController', ['$scope', function($scope) {
$scope.data = Data;
}])
.controller('SecondController', ['$scope', function($scope) {
$scope.data = {message: "panel"};
}]);
You must inject Data in the controller # .controller('FirstController', ['$scope', 'Data', function($scope, Data) { not list as module dependency # angular.module('app', Data). See the official DI documentation for more details and other options.
angular.module('app')
.controller('FirstController', ['$scope', 'Data', function($scope, Data) {
$scope.data = Data;
}])
.controller('SecondController', ['$scope','Data', function($scope, Data) {
$scope.data = {message: "panel"};
}]);
When you fetch a already created module you get by using angular.module('app'). You shouldn't be trying to inject the Data factory into the module but instead into the controller.
angular.module('app')
.controller('FirstController', ['$scope', 'Data', function($scope, Data) {
$scope.data = Data;
}])
.controller('SecondController', ['$scope', 'Data', function($scope, Data) {
$scope.data = {message: "panel"};
}]);
Use this:
angular.module('app')
.controller('FirstController', ['$scope', function($scope, Data) {
$scope.data = Data;
}])
.controller('SecondController', ['$scope', function($scope, Data) {
$scope.data = {message: "panel"};
}]);
what's the difference of this two code?
var myApp = angular.module('myApp', []);
myApp.controller('GreetingCtrl', function($scope) {
$scope.greeting = {
message: 'Hola!'
};
});
myApp.controller('HiCtrl', function($scope) {
$scope.double = {
text: 'Hello'
};
});
TO
var myApp = angular.module('myApp', []);
myApp.controller('GreetingCtrl',['$scope', function($scope) {
$scope.greeting = {
message: 'Hola!'
};
}]);
myApp.controller('HiCtrl',['$scope', function($scope) {
$scope.double = {
text: 'Hello'
};
}]);`
THAT having a ['$scope', next to function($scope) is not working if i have 2 controllers in 1 module?
Have a look at the AngularJS doc here. Basically, adding the ['$scope', allows you to use the Dependency Injection and still make it work with the JS minification process.
The minifier will change function($scope) in function(a) and you will lose the $scope dependency. Since minifiers don't compress Strings, ['$scope', will remain the same and AngularJS will be able to parse it.
FYI: if you are using Grunt and you don't want to use this ['$scope', notation, this module can be helpful.
angular.module('myApp', [])
.controller('GreetingCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.greeting = {
message: 'Hola!'
};
$http.get('http://www.google.com');
}]);
I have 2 controllers defined:
var myApp = angular.module('nestedControllersModule',[]);
myApp.controller('ParentController', ['$scope', function($scope) {
}]);
myApp.controller('ChildController', ['$scope', '$injector', function($scope, $injector) {
$injector.invoke(ParentController, this, {$scope: $scope});
}]);
This gives: ReferenceError: ParentController is not defined.
This code works only if ParentController is defined as:
function ParentController($scope) {}
I am trying to inject the parent in the child as then I can inherit the common functions defined in the parent.
var myApp = angular.module('nestedControllersModule',[]);
myApp.controller('ParentController', ['$scope', function($scope) {
$scope.name = 'ParentName';
$scope.Type = 'ParentType';
$scope.clickme = function() {
alert('This is parent controller "ParentController" calling');
}
}]);
myApp.controller('ChildController', ['$scope', '$injector', '$ParentController', function($scope, $injector, $ParentController) {
$injector.invoke(ParentController, this, {$scope: $scope});
$scope.name = 'Child';
}]);
myApp.controller('ParentController', ['$scope', function($scope) {
}]);
myApp.controller('ChildController', ['$scope', 'ParentController', function($scope, ParentController) {
// ok now you have ParentController
}]);
But I think you need to use Services to share data/functions between Controllers or using PubSub model:
What's the correct way to communicate between controllers in AngularJS?
This reduces coupling between parts of your app.
This is a basic workaround to achieve what you're after:
var myApp = angular.module('nestedControllersModule',[]);
myApp.factory('ParentControllerFactory', function () {
function ParentControllerFactory($scope) {
$scope.name = 'ParentName';
$scope.Type = 'ParentType';
$scope.clickme = function() {
alert('This is parent controller "ParentController" calling');
}
}
return (ParentControllerFactory);
})
.controller('ParentController', ['$scope', '$injector', 'ParentControllerFactory', function ($scope, $injector, ParentControllerFactory) {
$injector.invoke(ParentControllerFactory, this, {
$scope: $scope
});
}])
.controller('ChildController', ['$scope', '$injector', 'ParentControllerFactory', function ($scope, $injector, ParentControllerFactory) {
$injector.invoke(ParentControllerFactory, this, {
$scope: $scope
});
}]);
I say workaround because it's probably worthwhile looking into properly implementing a service to manage any commonality as previously mentioned (or better yet, splitting commonality into directives, clickme for example is a good candidate)
...also note that $injector.invoke(ParentControllerFactory as it is above will most likely chuck a hissy fit if/when you minify your scripts later on, so be careful where and how it used.
Consider using the Mixin pattern possible by using the $controller service.
In your example, you would replace the $injector service with the $controller service:
var myApp = angular.module('nestedControllersModule',[]);
myApp.controller('ParentController', ['$scope', function($scope) {
$scope.name = 'ParentName';
$scope.Type = 'ParentType';
$scope.clickme = function() {
alert('This is parent controller "ParentController" calling');
}
}]);
myApp.controller('ChildController', ['$scope', '$controller', '$ParentController', function($scope, $controller, $ParentController) {
$controller('ParentController',{$scope: $scope})
$scope.name = 'Child';
}]);
This is a good overview of using the $controller service:
http://vadimpopa.com/split-large-angularjs-controllers-using-the-mixin-pattern/