How to inject $rootScope into a service? - angularjs

how to inject a $rootScope into the factory definition for the following code (so the file can be minified):
(function() {
var signalRService = function($rootScope) {
// ...
};
var app = angular.module("App");
app.factory("signalRService", signalRService);
}());

The way to go about this is by supplying service definition as an array:
var signalRService = ['$rootScope', function($rootScope) {
// ...
}];
Argument will be minifed, but the injector will be based off the string in the array.
That said I'd suggest to revise whether this is really the way to go, as generally speaking relying on $rootScope is inadvisable, and so is using any kind of scopes directly in services/factories.

Related

Why can't I inject $scope into a factory in Angular?

I have a factory that needs to listen for a broadcast event. I injected $scope into the factory so I could use $scope.$on. But as soon as I add $scope to the parameter list I get an injector error.
This works fine:
angular.module('MyWebApp.services')
.factory('ValidationMatrixFactory', ['$rootScope', function($rootScope) {
var ValidationMatrixFactory = {};
return ValidationMatrixFactory;
}]);
This throws an injector error:
angular.module('MyWebApp.services')
.factory('ValidationMatrixFactory', ['$scope', '$rootScope', function($scope, $rootScope) {
var ValidationMatrixFactory = {};
return ValidationMatrixFactory;
}]);
Why can't I inject $scope into a factory? And if I can't, do I have any way of listening for events other than using $rootScope?
Because $scope is used for connecting controllers to view, factories are not really meant to use $scope.
How ever you can broadcast to rootScope.
$rootScope.$on()
Even though you can't use $scope in services, you can use the service as a 'store'. I use the following approach inspired on AltJS / Redux while developing apps on ReactJS.
I have a Controller with a scope which the view is bound to. That controller has a $scope.state variable that gets its value from a Service which has this.state = {}. The service is the only component "allowed" (by you, the developer, this a rule we should follow ourselves) to touch the 'state'.
An example could make this point a bit more clear
(function () {
'use strict';
angular.module('app', ['app.accounts']);
// my module...
// it can be defined in a separate file like `app.accounts.module.js`
angular.module('app.accounts', []);
angular.module('app.accounts')
.service('AccountsSrv', [function () {
var self = this;
self.state = {
user: false
};
self.getAccountInfo = function(){
var userData = {name: 'John'}; // here you can get the user data from an endpoint
self.state.user = userData; // update the state once you got the data
};
}]);
// my controller, bound to the state of the service
// it can be defined in a separate file like `app.accounts.controller.js`
angular.module('app.accounts')
.controller('AccountsCtrl', ['$scope', 'AccountsSrv', function ($scope, AccountsSrv) {
$scope.state = AccountsSrv.state;
$scope.getAccountInfo = function(){
// ... do some logic here
// ... and then call the service which will
AccountsSrv.getAccountInfo();
}
}]);
})();
<script src="https://code.angularjs.org/1.3.15/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="AccountsCtrl">
Username: {{state.user.name ? state.user.name : 'user info not available yet. Click below...'}}<br/><br/>
Get account info
</div>
</div>
The benefit of this approach is you don't have to set $watch or $on on multiple places, or tediously call $scope.$apply(function(){ /* update state here */ }) every time you need to update the controller's state. Also, you can have multiple controllers talk to services, since the relationship between components and services is one controller can talk to one or many services, the decision is yours. This approach focus on keeping a single source of truth.
I've used this approach on large scale apps... it has worked like a charm.
I hope it helps clarify a bit about where to keep the state and how to update it.

Call Angular directive controller method from another controller

I have a directive which is associated with one controller and the functions in my controller defined as
MyFormController.prototype.addNewRow = function addNewRow() {
//Adding row code
};
I want to call this method from another controller, possible ways?
I ve user the service and moved the code into that service which is shared across the controllers, however the service code does the DOM manipulation, and then i guess the next question would be that can we use $compile in a service test case
service or factory is used to share data between controller.so it would be best to define function in service and factory.
demo:
(function() {
angular.module('app', [])
.service('svc', function() {
var svc = {};
svc.method = function() {
alert(1);
}
return svc;
})
.controller('ctrl', [
'$scope', 'svc', function($scope, svc) {
svc.method();
}
]);
})();
You should not!!!
That defeats the whole purpose of modularity.
If possible try to make the function generic and create a service/factory. Now both the places where you need, use the same generic function defined in service and do their stuff.
Otherwise you can also look at events to make changes accordingly.
Look at this blog post:
http://ilikekillnerds.com/2014/11/angularjs-call-controller-another-controller/
Last but the worst solution is (avoid using this, this is literally an aweful way) is catching the element inside directive and getting its scope and taking the function from it.
Example,
var otherControllerFunc = $(".inside-directive").scope().yourfunc;

How to properly refactor this kind of angularjs code?

I have an angularjs file that uses a much different style of coding than I'm using, and I need to recreate the functionality. For instance, in a service declaration, a function is defined and passed in as the second paramater of .service('someservicehere', functionparam)
First of all, all of the parts of the app(controllers, services, factories, etc) all start out like so:
var self = this;
1) Is this the $scope object normally passed in as a parameter, such as in a controller?
2) Is it the same in a service, such as this one?
function userService($http, API, auth) {
var self = this;
self.getQuote = function() {
return $http.get(API + '/auth/quote')
}
// add authentication methods here
self.register = function(username, password){
return $http.post('/auth/register',{
username: username,
password: password
})
}
self.login = function(username, password){
return $http.post('/auth/signin', {
username: username,
password: password
})
}
Below, in the same file, the service is implemented like so (line 3)
angular.module('app', ['ui.router'])
.factory('authInterceptor', authInterceptor)
.service('user', userService)
.service('auth', authService)
.constant('API', 'localhost:3000')
.config(function($httpProvider, $stateProvider, $urlRouterProvider) {
$httpProvider.interceptors.push('authInterceptor');
})
.controller('Main', MainCtrl)
})();
Can I effectively follow that rule (that self be rewritten as $scope and the dependencies properly injected) when refactoring the code? I have been following angularjs tutorials (and usually completing them the same day) for about a month or so now, and have never encountered this style of writing code. What are the benefits or drawbacks, and why do it this way? Are there any resources on the web I can find for this?
I apologize if this is a duplicate. I don't even know what this style of coding is, as I've never encountered it, and had no word (or words) to search for on google when researching.
Thanks in advance!
1) No, it's the instance of the controller, service, factory etc. Not the scope. When using controllerAs syntax, your controller becomes a property on the scope. So let's say you defined the controllerAs name of 'Main' to be 'mainCtl'.
var self = this; // 1st line of the controller
self.foo = 'BAR';
$scope.foo = 'BEEP';
And html like this:
<span>{{mainCtl.foo}} {{foo}}</span>
That would evaluate to:
BAR BEEP
2) No, typically services don't have any $scope.
var self = this; // 1st line of the service
self.foo = 'bar';
and in your controller:
myModule.controller('Main', function($scope, MyService){
console.log(MyService.foo); // 'bar'
});
So in each case this is targeting the instance of the controller, service etc, not the $scope. This isn't an angular thing, this is more about functional programming.
The reason for defining a variable for this (e.g. var self = this) is because these functions are being treated by the devs as constructor functions. self will refer to the instance created when new is used on that function (e.g. var objectInstance = new constructorFunction())
It also helps to have a variable for this because this will have a different meaning depending on which function calls it, but not if you create that variable first.

Angular Dependencies Between Modules

I'm facing a problem using Dependency Injection between modules.
I have a module that implements a directive I need to use in other applications.
I added the dependency from this module in another app declaration like this:
angular.module('mainApp', ['ngRoute', 'directiveApp']);
However, the methods implemented into directiveApp.controller, doesn't seem to be visible from a page of MainApp, since the directive can't run a method it needs from their controller.
I know it's a little confusing, so I put an example in this plunker, that shows the problem I'm facing.
When you inject another module into your own, the controllers and directives it implements become available, but you need to use them properly.
The way you are trying to do is not possible, you can do something like this:
http://plnkr.co/edit/peHH226vxtkI48RFZ3Eq?p=preview
<body ng-controller="MainCtrl">
<h1>Value: {{name}}!</h1>
<button ng-click="mainModule()">Call a function in the main module!</button>
<div ng-controller="SubCtrl">
{{name}}
<button ng-click="dependentModule()">Call a function in the dependent module!</button>
</div>
</body>
But notice that you have two different $scopes and consequently two different name variables.
That means your dependentModule() function belongs to your SubCtrl and you can only use it inside its own $scope
That's not recommended, but if you really need to, you can use the other controllers on your own methods and then copy the results:
http://plnkr.co/edit/ranK9n08NNVuSKIGX15G?p=preview
main.controller("MainCtrl", function($scope, $controller) {
$scope.name = "Initial value";
$scope.mainModule = function() {
$scope.name = "a function in the same module";
};
$scope.bridgeFunction = function(){
// Create a new scope
var injectedScope = $scope.$new();
// Use it on the other controller
$controller('SubCtrl',{$scope : injectedScope });
// Call the methdo on the controller
testCtrl1ViewModel.dependentModule(); //And call the method on the newScope.
// Copy the result from that scope into your own
$scope.name = testCtrl1ViewModel.name;
}
});
A third option is to merge the two scopes, although this can get very messy, it is possible:
http://plnkr.co/edit/1NKStMuYy0e00dhuWKUD?p=preview
main.controller("MainCtrl", function($scope, $controller) {
$scope.name = "Initial value";
//This can get very messy, but it is possible to merge the two scopes:
$controller('SubCtrl',{$scope : $scope });
$scope.mainModule = function() {
$scope.name = "a function in the same module";
};
});
Hope that helps

angularjs saving $scope via a closure

Disclaimer that I'm new to angularjs :)
I have a controller that delegates to a service and I'm trying to preserve the $scope so I can scope.apply after setting properties:
var Build = function($scope, $http, mango) {
var scope = $scope;
$scope.BuildManagerSubmit = function(selectedProfile) {
mango.buildMango(selectedProfile.def, function(profiledef) {
// bunch of property assignments on selectedProfile ...
scope.$apply();
}, scope);
};
};
controllers.controller('Build', ['$scope', '$http', 'mango', Build]);
Notice that I'm using the closure to save the scope and passing it in to the service (omitted for brevity). The service calls me back like cb.call(context, ...) so I maintain access to scope. This is all working fine, but I'm more concerned with whether there's a better idiom. I don't see a lot of examples of maintaining $scope when delegating out to services like this.
EDIT: this application is using node-webkit and the 'mango' service essentially is interacting with the file system to call out to shell scripts, etc.
I would make the mango service take care of that (inject $rootScope in it), and perhaps use promises to replace callbacks so it would look like that:
var Build = function($scope, $http, mango) {
$scope.BuildManagerSubmit = function(selectedProfile) {
selectedProfile.profileDef = mango.buildMango(selectedProfile.def);
// do something when profileDef returned? (not always necessary)
selectedProfile.profileDef.then(function(profileDef) {
});
};
};
controllers.controller('Build', ['$scope', '$http', 'mango', Build]);

Resources