Say I have a factory named MyFactory and I inject it into several controllers. How can I access the controllers scope inside the factory?
The only way I currently think of on how to do this is as follows:
app.factory('MyFactory', function() {
return function($scope) {
myPublicFunc: function() {
$scope.$on('$destroy', function() { ... });
}
}
});
app.controller('MyController1', ['$scope', MyFactory', function($scope, Myfactory) {
var factory = new MyFactory($scope);
factory.myPublicFunc();
});
But is there any other way where I can just return { } instead of function($scope) { } in MyFactory and use the factory directly (MyFactory.myPublicFunc) instead of having to create a new instance with the new keyword and still access each controller's $scope?
if you use a .service instead of .factory you will already have a singleton instance in a controller once you inject it via DI
and then you can do for example
module.service('myService', function() {
return {
myPublicFn: function() {}
}
});
and
module.controller('myCtrl', function(myService, $scope) {
$scope.publicFn = myService.myPublicFn;
});
Related
I have this controller A which I'm trying to inject in every other controller.
What controller A does is, it communicates with a factory (which does some authentication services, communicates with database)
My factory looks like this and I named it myFactoryServices.js and included the link to it in my index page.
(function() {
angular
.module('myApp.myFactoryServices', [])
.factory('FactoryService', ["$http", "$location", function($http, $location){
var my = this;
my.someFunction = function()
{
//communiate with backend and return data
}
return my;
}]);
})();
and my Controller A looks like this:
(function() {
angular
.module('myApp.ControlA', [])
.controller('ControllerA', function($scope,$routeParams, FactoryService) {
var my = this;
FactoryService.someFunction();
});
})();
And I am trying to inject this controller in every other controller, but it does not work. I am pretty new to this kind of programming, can anyone tell me where I made mistake?
This is how I tried injecting a controller into another.
(function() {
angular
.module('myApp.ControlB', [])
.factory('ControllerBService', function($http) {
var baseUrl = 'backendurl/';
return {
getInfo: function() {
return $http.get(baseUrl+ 'getInfo');
}
};
})
.controller('ControllerB', function($scope,$routeParams, ControllerBService,ControllerA) {
var my = this;
});
})();
No error is coming, and the controller is not getting injected as I am not able to use those factory services. is this the correct method?
First of all you cannot inject controller to another controller, and One simple solution would be, instead of having each angular modules for each components, declare a module and add the factory service to controllers as dependency.
Code:
var app = angular.module('myApp', []);
app.factory('FactoryService', ["$http", "$location", function($http, $location){
var my = this;
my.someFunction = function()
{
//communiate with backend and return data
}
return my;
}]);
app.controller('ControllerA', function($scope,$routeParams, FactoryService)
{
var my = this;
FactoryService.someFunction();
});
app.controller('ControllerB', function($scope,$routeParams, FactoryService)
{
var my = this;
FactoryService.someFunction();
});
Controllers are not injectable, because controller is not singleton. Controllers are constructor functions used to create instances of controllers. For example you can have multiple instances of one controller in your app:
angular.module('app', []);
angular
.module('app')
.controller('Example', function () {
this.x = Math.random();
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.js"></script>
<div ng-app="app">
First instance: <br>
<div ng-controller="Example as Ex1">
{{Ex1.x}}
</div>
Second instance: <br>
<div ng-controller="Example as Ex2">
{{Ex2.x}}
</div>
</div>
So if you want to share some behavior between controller you should use factory instead.
To inject a controller into another controller, use the $controller service.
app.controller('ControllerB', function($scope,$routeParams, $controller) {
var my = this;
$scope.ctrlA = $controller("ControllerA", {$scope: $scope});
});
The above example creates an instance of ControllerA as ctrlA with its $scope injected with the scope of the parent controller.
For more information, see AngularJS $controller Service API Reference.
I have two controllers:
<div ng-controller="Main">
<div ng-controller="Map"></div>
</div>
In controller Main I have variable $scope.mapCoord;
How I can to pass this variable in controller Map?
Use a service. For example:
var app = angular.module('myApp', [])
app.service('sharedProperties', function () {
var mapCoord= 'Test';
return {
getProperty: function () {
return mapCoord;
},
setProperty: function(value) {
mapCoord= value;
}
};
});
Inside your Main controller
app.controller('Main', function($scope, sharedProperties) {
$scope.mapCoord= sharedProperties.setProperty("Main");
});
Inside your Map controller
app.controller('Map', function($scope, sharedProperties) {
$scope.mapCoord= sharedProperties.getProperty();
});
Here's a fiddle for you. JSFiddle
You use events to pass it between controllers using by $broadcast, $emit and $on
Working with $scope.$emit and $scope.$on
http://mariuszprzydatek.com/2013/12/28/sharing-data-between-controllers-in-angularjs-pubsub-event-bus-example/
In your "Map" controller, set "Main" scope to current scope such as below :
app.controller('Map', ['$scope','$controller',function($scope, $controller) {
$controller('Main', {
$scope : $scope
});
}]);
After that you can access all the scope of Main controller from his son controller :
app.controller('Map', ['$scope','$controller',function($scope, $controller) {
$controller('Main', {
$scope : $scope
});
var coord = $scope.mapCoord;
}]);
I have my CartDropdownController that can be configured (i.e. setting autoCloseDelay) and I'm facing the following problem: how to inject the controller in angular.run() method?
angular.module('app')
.controller('CartDropdownController', ['$scope', function ($scope) {
this.autoCloseDelay = 3000;
this.setAutoCloseDelay = function (autoCloseDelay ) {
this.autoCloseDelay = autoCloseDelay;
};
// $scope variables here...
}]);
I know that services can be injected in .run() (like $http), but my controller is not a service (and I don't know how to make it a service...).
Edit: why? I don't want my controller to depend on values/constants:
angular.module('app')
.value('config', {
cart: {autoCloseDelay: 1500}
})
.controller('CartDropdownController', [
'$scope',
'config',
function ($scope, config) {
var autoCloseDelay = config.cart.autoCloseDelay || 3000;
// ...
}
]);
docs say You can only inject instances (not Providers), and yes controller itself is also an instance, just like a service.
Now See this example:
var myApp = angular.module('myApp', []);
myApp.factory('aProvider', function() {
console.log("factory invoked");
return{
fun:function(from){
console.log("factory from"+from);
}
}
});
myApp.directive("test1", function() {
console.log("directive setup");
return {
compile: function() {console.log("directive compile");}
}
});
myApp.directive("test2", function() {
return {
link: function() {console.log("directive link");}
}
});
myApp.run(function(aProvider) {
console.log("app run");
// aProvider.fun('from run');
});
myApp.config( function() {
console.log("app config");
});
myApp.controller('myCtrl', function($scope) {
console.log("app controller");
});
And the result:
app config
(index):24 factory invoked
(index):46 app run
(index):33 directive setup
(index):35 directive compile
(index):56 app controller
(index):41 directive link
What happens here:
config block executed
factory is invoked(instances, services or factories)
run executed
directives set
controllers initialized
directives linked to the page
Now here, you see run is executed first and controllers are initialized afterwords. This is why controllers cant be injected into app.run()
I'm trying to unit test a controller in AngularJS using Jasmine. The controller has slightly different syntax than most documentation I can find and I'm getting this error...
http://errors.angularjs.org/1.2.15/$injector/unpr?p0=propertiesProvider%20%3C-%20properties
The controller...
myApp.controller('myController', function($scope, $rootScope, param) {
param.info.get().then(function(example){
//...
});
});
The test js...
describe('myApp', function() {
var $scope, $rootScope, param, createController, properties;
beforeEach(module('myApp'));
debugger; //runs
beforeEach(inject(function($injector) {
debugger; //doesn't run
$rootScope = $injector.get('$rootScope');
properties = $injector.get('properties');
param = $injector.get('param');
$scope = $rootScope.$new();
var $controller = $injector.get('$controller');
createController = function() {
return $controller('myController', {
'$scope': $scope,
'$rootScope':$rootScope,
'properties':properties,
'param':param,
});
};
}));
var a;
it('should pass this basic test no matter what', function() {
a = true;
expect(a).toBe(true);
});
});
Param definition...
myApp.factory("param", function($http) {
return {
info: {
get: function() {
return $http.get(myApp.url("/param/info")).then(function(response) {
return response.data.data;
});
}
}
}
myApp.run...
myApp.run(['$http', '$rootScope', 'properties', function($http, $rootScope, properties){
...
}]);
If you look at the error carefully it says error in propertiesProvider, you are injecting properties in your test , and hence it's looking for propertiesProvider which doesn't exist . so it throws error.
If properties is an angular Service and you are injecting that in your controller , while testing you need not inject that service again to your test, angular mock takes care of that .
I'll suggest you use npm package generator-yosapy to bootstrap your controller test
I am trying to call a scope function inside the controller. My aim is to call the function in the load itself.
var app = angular.module('myApp', []);
app.controller('customersCtrl', function($scope, $http) {
$scope.functionname();
$scope.functionname = function() {}
});
You can directly call the function in controller.
app.controller('customersCtrl', function($scope, $http) {
functionname();
function functionname {
//do something.
}
});
If you are looking to reuse the function outside controller then use Service as controllers are not injectable.
Read johnpapa style guide which shows best practices: https://github.com/johnpapa/angular-styleguide
app.controller('customersCtrl', function(someService) {
var vm = this;
activate();
function activate() {
// Do something.. You can get the data from your service
}
});
Then do your $http in services then inject it in your controller/s.
Best way is to use services:
var app = angular.module('myApp', []);
app.service('SomeService', ['$state', function ($state) {
this.someFunction = function() {
return "some value";
};
}]);
app.controller('customersCtrl', function($scope, $http, SomeService) {
SomeService.someFunction();
});