I am not able to access a service inside my controller method.
AppController.$inject = ['$scope', 'appService'];
function AppController($scope, appService) {
$scope.name = "World";
$scope.clicked = function() {
//am not able to access appService here
/*
appService.setName("john");
$scope.name = getName();
*/
$scope.name = "button clicked";
}
}
http://plnkr.co/edit/UgHmtCbkxeyluTPJOG4T?p=info
The service is accessible when the controller gets created, but not when clicked() is called in the controller. Please let me know if I am missing something here.
I was trying to create a directive (something like a locale select dropdown). I wanted the directive to have its controller and its own service. My idea is that the controller would handle the languageChange() method when the user changes the dropdown and sets the language in a service, so that I can inject this service in any other part of the application.
That's when I had problems in accessing the service inside my controller method(languageChange())
I think if I get the basic example right, I will be able to proceed with my language change directive.
You forgot add the appService to getName()
Use this:
appService.setName("john");
$scope.name = appService.getName();
Instead of:
appService.setName("john");
$scope.name = getName();
Running example: http://plnkr.co/edit/Hh9g7H9PI9JhNdbAhqdT?p=preview
Related
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.
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;
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.
I have checked some of the topics for this matter and i got an understanding of controllers are there to initiate scope and i need to use services for this matter but i dont know how.
so here is the problem. i have index page which body has only one div and inside the div i have ng-include listening to a function called viewFile() which is described on controllerA. on the first initial attempt i load a view called login.html and display it. when users logs in and its successful, which are handled in controllerB, i return a token and now i want to load main.html page using viewFile() in controllerA. is there a call back function or notify controller or something for this? or can i write a service that takes care of this for me?
I'm not using ngRoute because i dont want my URL to change to mysite.com/#/login.html and then mysite.com/#/main.html
.controlle("A", function ($scope, sharedVariable){
$scope.token = sharedVariable.getToken();
$scope.viewFile = function(){
if($scope.token == "")
return "view/Login.html";
else
return "view/main.html";
}
}
.controller("B", function ($scope, $http, sharedVariable)){
http({
get ...
.success: function(data){
$scope.token = sharedVariable.setToken();
// INVOKE viewFile from above controller
}
})
}
and here is the index.html body part
<body>
<div ng-controller="A"><ng-include src="viewFile()"></ng-include></div>
</body>
look at this simple example http://jsfiddle.net/derkoe/T85rg/presentation/ here personService.person is shared between two controllers similarly you can write your viewFile function in one service like personService. Then call personService.viewFile from any controller. You can pass $scope as its argumen. Something like below
var myModule = angular.module('myModule', []);
myModule.factory('myService', function($rootScope) {
var sharedService = {};
sharedService.viewFile = function($scope) {
if($scope.token == "")
return "view/Login.html";
else
return "view/main.html";
};
return sharedService;
});
If you want to change the view using different condition define you viewFile function in some service or put it in routescope. Then you can call it from multiple controllers. But I don't think without refresh angularjs will be able to load a different view html
I have an angularjs app with some controllers.
At some point, I need to access a function defined inside a controller, but the place where the function is gonna be called is not inside the angularjs APP.
I'll try to build a simple scenario:
app.controller('TaskController', function ($scope, $routeParams, $window, TaskEngine, PortalUtil) {
$scope.closeTask = function() {
$scope.openTask = false;
$scope.openedTaskUrl = undefined;
}
});
-- Some other place in my web app, outside of the angular APP.
<button onclick="closeTask();">
The "closeTask()" function is never accessible, because its out of scope.
I tried to define it in the window object
$window.closeTask = function() {
$scope.openTask = false;
$scope.openedTaskUrl = undefined;
}
});
Now, my function is visible, but the variables "openTask" and "openedTaskUrl" are not.
Is it possible to do what I want?
Basically, I have a controller, and I need to access one function anywhere, to control the behaviour of a menu.
Thanks!
I would not use $window for this. Instead, Angular has a nice feature which lets not Angular code to interact with it. Using Angular.element you can access data or functions defined in Angulars Scope.
var $scope = angular.element(document.querySelector('[ng-app=app]')).scope();
$scope.$apply(function() {
$scope.print("Hello world");
});