Inject factory into controller function in angularjs - angularjs

I am trying to code a factory and use it on a controller
.controller('View2Ctrl', ['$scope', 'Alert', function($scope, Alert) {
this works inside the controller but when I am trying to access it inside a function it's undefined.
$scope.test_function = function(Alert) {
Alert.some_method -> undefined.
};

$scope.test_function = function() { // remove Alert
Alert.some_method -> undefined.
};
if you inject the service into a controller you dont need to inject into a function inside that controller
check this one :)

Related

How to call a API in Angular controller

I'm facing a problem with angular JS Controller function. I have a controller and in that controller I have bunch of functions which are getting called from a service which contains HTTP get and post requests.
To be specific my question is inside a controller, when I try to write:
$scope.functionName = function()
{
//some code
}
My function doesn't get called at all. And when I do the following my function gets called but the scope goes undefined for rest of the functions.
app.controller("ControllerName", function ($scope, ServiceName) {
getAll();
getAppKey();
getAppDefaults();
function getAll(){//some code}
function getAppKey(){//some code}
function AppDefaults(){//some code
})
I'm not sure where I'm going wrong. I would really appreciate anyone's help who can help me out with this issue.
I think you are defining function with $scope and calling function without $scope.
This code will work:
app.controller("ControllerName", function ($scope, ServiceName) {
$scope.getAll = function{
console.log("function called");
}
$scope.getAll();
})
And this code will not work as expected:
app.controller("ControllerName", function ($scope, ServiceName) {
$scope.getAll = function{
console.log("function called");
}
getAll();
})
'...bunch of functions which are getting called from a service...' ?
You can't call function from controller in service. What you can do is to use functions from service in controller.
If you want to use methods from service inside your controller, first inject service(you already did that),
then call it:
ServiceName.getAll();
ServiceName.getAppKey();
...
etc.
If you want to use this functions from controller, make another service/factory put this functions inside that service, inject service2 in service and again you can use them like:
ServiceName2.getAll();
ServiceName2.getAppKey();
I am not sure what are you trying to acomplish, maybie this?
this code works:
app.controller('MainCtrl', function($scope) {
$scope.submit = function() {
alert("called.........");
}
defaultFunction = function() {
alert("defaultFunction called.........");
}
defaultFunction();
});
$scope is added when you want to use in view, if you need to use it in controller, no need for $scope
you can change http://jsfiddle.net/B9RsQ/45/ to test it

How do I use services in Angular to store variables?

How do I use services to store variables so that I can access it in previous controller on pressing back button?
For example:
.controller('myCtrl', function($scope, myservice) {
console.log(myservice.myvar.myval)
// output: undefined pressing back button
});
.controller('myCtrl2', function($scope, myservice) {
myservice.myvar.myval = "This I want in controller myCtrl on pressing back button"
console.log(myservice.myvar.myval)
// outputs the value
});
If services are not the best approach and I should use $rootScopethen will it do the job.
P.S angular.module and myservice are defined.
You need to use getter-setter for this.
For Example:
angular.module('MyModule', [])
.service('myservice', function () {
this.myval = "value";
this.getValue = function () { return this.myval }; //getter
this.setValue = function (val) { this.myval = val }; //setter
})
.controller('myCtrl', function($scope, myservice) {
console.log(myservice.getValue());
// get the value here
});
.controller('myCtrl2', function($scope, myservice) {
myservice.setValue("This I want in controller myCtrl on pressing back button");
// Set the value here
});
This is for the reference only. Please don't copy-paste and run code.
Angular services are singletons and can be freely shared among components, which have access to dependency injection. You can define a closure with a module pattern of getters and setters or directly attach properties to the object you intend to return.
I see 4 options, you can store it in a service, in $rootScope, in localStorage for persistent storage, and in sessionStorage to store datas only during the application lifetime. There's btw a nice module that wrap localStorage and sessionStorage, and make its use simpler :
http://ngmodules.org/modules/ngStorage

What is the difference between two scopes in the same controller (one from a service) to a directive?

I've got the below controller with two scope variables and only one passes through to my directive?
.controller('newsController', ['$scope', 'gasPrices',
function($scope, gasPrices) {
gasPrices.success(function(data) {
$scope.gasFeed = data.series[0];
});
$scope.myData02 = [2.095,2.079,2.036,1.988,1.882,1.817,1.767,1.747];
}])
;
I've got a directive that accepts one scope but not the other?
This works
<line-chart chart-data="myData02"></line-chart>
This doesn't
<line-chart chart-data="gasFeed"></line-chart>
Do you know why?
You have to delay instantiating the directive until the data from your async service is available. Something like:
<line-chart ng-if="gasFeed" chart-data="gasFeed"></line-chart>
This should not instantiate the directive until the gasFeed scope property has data.
Try this:
.controller('newsController', ['$scope', 'gasPrices',
function($scope, gasPrices) {
//Create a object that will be pass in the directive, then when this variable
//it's loaded, the value in the directive (if the scope of the directive uses the '=' binding) will be updated
$scope.gasFeed = {};
gasPrices.success(function(data) {
$scope.gasFeed = data.series[0];
});
$scope.myData02 = [2.095,2.079,2.036,1.988,1.882,1.817,1.767,1.747];
}]);
Yes.
Here, in your example you can access gasFeed scope only when when there is a success callback from the service. Hence, till then myData02 scope will be loaded.
If you want to access both. Then try this :
.controller('newsController', ['$scope', 'gasPrices',
function($scope, gasPrices) {
gasPrices.success(function(data) {
$scope.gasFeed = data.series[0];
$scope.myData02 = [2.095,2.079,2.036,1.988,1.882,1.817,1.767,1.747];
});
}]);

Execute $http call in angular .run() finished after controller init

I am trying to make an $http call in order to store a JSON into $rootScope in the .run() function in an Angular app but the call is done after the controllers are loaded and I cannot use any of the data from the call. Can anyone help me with this issue?
Also tried to see what happens with console.log, the output is "b" then "a" and for $rootScope.xml is undefined
var app = angular.module('lobby', ['ngRoute']);
app.run(['$rootScope','$http', function($rootScope, $http) {
$http.get(Main.constants.BASEURL+'x.xml').success(function(xml) {
$rootScope.xml = $.xml2json(xml.data);
console.log('a');
});
}]);
app.controller('CategoriesController', function($rootScope) {
console.log($rootScope.xml);
console.log('b');
});
You can try placing a $watch on $rootScope.xml and listen for a new value, which should occur when the $http call resolves & xml scope variable value gets changed.
Code
app.controller('CategoriesController', function($rootScope) {
$rootScope.$watch('xml', function(newValue, oldValue) {
if($rootScope.xml) {
console.log($rootScope.xml);
}
});
});

How do I inject a controller into another controller in AngularJS

I'm new to Angular and trying to figure out how to do things...
Using AngularJS, how can I inject a controller to be used within another controller?
I have the following snippet:
var app = angular.module("testApp", ['']);
app.controller('TestCtrl1', ['$scope', function ($scope) {
$scope.myMethod = function () {
console.log("TestCtrl1 - myMethod");
}
}]);
app.controller('TestCtrl2', ['$scope', 'TestCtrl1', function ($scope, TestCtrl1) {
TestCtrl1.myMethod();
}]);
When I execute this, I get the error:
Error: [$injector:unpr] Unknown provider: TestCtrl1Provider <- TestCtrl1
http://errors.angularjs.org/1.2.21/$injector/unpr?p0=TestCtrl1Provider%20%3C-%20TestCtrl1
Should I even be trying to use a controller inside of another controller, or should I make this a service?
If your intention is to get hold of already instantiated controller of another component and that if you are following component/directive based approach you can always require a controller (instance of a component) from a another component that follows a certain hierarchy.
For example:
//some container component that provides a wizard and transcludes the page components displayed in a wizard
myModule.component('wizardContainer', {
...,
controller : function WizardController() {
this.disableNext = function() {
//disable next step... some implementation to disable the next button hosted by the wizard
}
},
...
});
//some child component
myModule.component('onboardingStep', {
...,
controller : function OnboadingStepController(){
this.$onInit = function() {
//.... you can access this.container.disableNext() function
}
this.onChange = function(val) {
//..say some value has been changed and it is not valid i do not want wizard to enable next button so i call container's disable method i.e
if(notIsValid(val)){
this.container.disableNext();
}
}
},
...,
require : {
container: '^^wizardContainer' //Require a wizard component's controller which exist in its parent hierarchy.
},
...
});
Now the usage of these above components might be something like this:
<wizard-container ....>
<!--some stuff-->
...
<!-- some where there is this page that displays initial step via child component -->
<on-boarding-step ...>
<!--- some stuff-->
</on-boarding-step>
...
<!--some stuff-->
</wizard-container>
There are many ways you can set up require.
(no prefix) - Locate the required controller on the current element. Throw an error if not found.
? - Attempt to locate the required controller or pass null to the link fn if not found.
^ - Locate the required controller by searching the element and its parents. Throw an error if not found.
^^ - Locate the required controller by searching the element's parents. Throw an error if not found.
?^ - Attempt to locate the required controller by searching the element and its parents or pass null to the link fn if not found.
?^^ - Attempt to locate the required controller by searching the element's parents, or pass null to the link fn if not found.
Old Answer:
You need to inject $controller service to instantiate a controller inside another controller. But be aware that this might lead to some design issues. You could always create reusable services that follows Single Responsibility and inject them in the controllers as you need.
Example:
app.controller('TestCtrl2', ['$scope', '$controller', function ($scope, $controller) {
var testCtrl1ViewModel = $scope.$new(); //You need to supply a scope while instantiating.
//Provide the scope, you can also do $scope.$new(true) in order to create an isolated scope.
//In this case it is the child scope of this scope.
$controller('TestCtrl1',{$scope : testCtrl1ViewModel });
testCtrl1ViewModel.myMethod(); //And call the method on the newScope.
}]);
In any case you cannot call TestCtrl1.myMethod() because you have attached the method on the $scope and not on the controller instance.
If you are sharing the controller, then it would always be better to do:-
.controller('TestCtrl1', ['$log', function ($log) {
this.myMethod = function () {
$log.debug("TestCtrl1 - myMethod");
}
}]);
and while consuming do:
.controller('TestCtrl2', ['$scope', '$controller', function ($scope, $controller) {
var testCtrl1ViewModel = $controller('TestCtrl1');
testCtrl1ViewModel.myMethod();
}]);
In the first case really the $scope is your view model, and in the second case it the controller instance itself.
I'd suggest the question you should be asking is how to inject services into controllers. Fat services with skinny controllers is a good rule of thumb, aka just use controllers to glue your service/factory (with the business logic) into your views.
Controllers get garbage collected on route changes, so for example, if you use controllers to hold business logic that renders a value, your going to lose state on two pages if the app user clicks the browser back button.
var app = angular.module("testApp", ['']);
app.factory('methodFactory', function () {
return { myMethod: function () {
console.log("methodFactory - myMethod");
};
};
app.controller('TestCtrl1', ['$scope', 'methodFactory', function ($scope,methodFactory) { //Comma was missing here.Now it is corrected.
$scope.mymethod1 = methodFactory.myMethod();
}]);
app.controller('TestCtrl2', ['$scope', 'methodFactory', function ($scope, methodFactory) {
$scope.mymethod2 = methodFactory.myMethod();
}]);
Here is a working demo of factory injected into two controllers
Also, I'd suggest having a read of this tutorial on services/factories.
There is no need to import/Inject your controller in JS. You can just inject your controller/nested controller through your HTML.It's worked for me.
Like :
<div ng-controller="TestCtrl1">
<div ng-controller="TestCtrl2">
<!-- your code-->
</div>
</div>
you can also use $rootScope to call a function/method of 1st controller from second controller like this,
.controller('ctrl1', function($rootScope, $scope) {
$rootScope.methodOf2ndCtrl();
//Your code here.
})
.controller('ctrl2', function($rootScope, $scope) {
$rootScope.methodOf2ndCtrl = function() {
//Your code here.
}
})
<div ng-controller="TestCtrl1">
<div ng-controller="TestCtrl2">
<!-- your code-->
</div>
</div>
This works best in my case, where TestCtrl2 has it's own directives.
var testCtrl2 = $controller('TestCtrl2')
This gives me an error saying scopeProvider injection error.
var testCtrl1ViewModel = $scope.$new();
$controller('TestCtrl1',{$scope : testCtrl1ViewModel });
testCtrl1ViewModel.myMethod();
This doesn't really work if you have directives in 'TestCtrl1', that directive actually have a different scope from this one created here.
You end up with two instances of 'TestCtrl1'.
The best solution:-
angular.module("myapp").controller("frstCtrl",function($scope){
$scope.name="Atul Singh";
})
.controller("secondCtrl",function($scope){
angular.extend(this, $controller('frstCtrl', {$scope:$scope}));
console.log($scope);
})
// Here you got the first controller call without executing it
use typescript for your coding, because it's object oriented, strictly typed and easy to maintain the code ...
for more info about typescipt click here
Here one simple example I have created to share data between two controller using Typescript...
module Demo {
//create only one module for single Applicaiton
angular.module('app', []);
//Create a searvie to share the data
export class CommonService {
sharedData: any;
constructor() {
this.sharedData = "send this data to Controller";
}
}
//add Service to module app
angular.module('app').service('CommonService', CommonService);
//Create One controller for one purpose
export class FirstController {
dataInCtrl1: any;
//Don't forget to inject service to access data from service
static $inject = ['CommonService']
constructor(private commonService: CommonService) { }
public getDataFromService() {
this.dataInCtrl1 = this.commonService.sharedData;
}
}
//add controller to module app
angular.module('app').controller('FirstController', FirstController);
export class SecondController {
dataInCtrl2: any;
static $inject = ['CommonService']
constructor(private commonService: CommonService) { }
public getDataFromService() {
this.dataInCtrl2 = this.commonService.sharedData;
}
}
angular.module('app').controller('SecondController', SecondController);
}

Resources