Factory in angularJS - javascript

Im trying to use a factory in angularJS, but I don't work as expected.
Here is my controller:
as.controller('Test', ['testFactory', function($scope, $http, $rootScope)
{
$http.get($rootScope.appUrl + '/nao/test/test')
.success(function(data, status, headers, config) {
$scope.test = data;
});
$scope.form = {};
$scope.submitForm = function(isValid) {
if(isValid)
{
testFactory.testFactoryMethod(function($http) {
$scope.test = data;
});
}
};
}]);
As you can see, I "include" my factory to the controller.
Here is my factory:
.factory('testFactory', function($http) {
return {
testFactoryMethod: function(callback) {
return $http('http://127.0.0.1:81/test/test', data).success(function(data) { callback(data);
});
}
};
});
When I run this, I get this error message:
Error: $http is undefined
#http://127.0.0.1:82/nao/js/controllers.js:82:3
Anyone who can help me?

This happens because of Angular $injector. When you provide an array as 2nd argument for .controller, the $injector tries to find all dependencies listed on it by their name and then inject them to the array's last element (which must be a function), so in your case, this is what happens:
'testFactory' -> $scope
undefined -> $http
undefined -> $rootScope
Your code should be either like this:
as.controller('Test', ['$scope', '$http', '$rootScope', 'testFactory', function($scope, $http, $rootScope, testFactory)
{
// ...
... or like this:
as.controller('Test', function($scope, $http, $rootScope, testFactory)
{
// ...
Edit: As #sp00m stated, the second example should not be used if you are going to uglify (minify) your code, because the uglifier algorithm will replace those identifiers with something like:
function(a, b, c, d)
And then AngularJS will not be able to find those dependencies anymore, whereas the first example would look like this:
['$scope', '$http', '$rootScope', 'testFactory', function(a, b, c, d)
Which is valid, because you are explicitly telling Angular which dependencies it must inject.

There is a problem with the dependencies in your controller. The names you have as strings in the array don't match the arguments to your factory function.
This should work:
as.controller('Test', ['$scope', '$http', '$rootScope', 'testFactory', function($scope, $http, $rootScope, testFactory)
{
$http.get($rootScope.appUrl + '/nao/test/test')
.success(function(data, status, headers, config) {
$scope.test = data;
});
$scope.form = {};
$scope.submitForm = function(isValid) {
if(isValid)
{
testFactory.testFactoryMethod(function($http) {
$scope.test = data;
});
}
};
}]);

I think you're forgetting the $http.post:
$http(url, data) should be $http.post(url, data)
And what others have said before, you need the testFactory injected in the controllers function.

You should declare your controller like this
as.controller('Test', ['$scope', '$http', '$rootScope', 'testFactory', function($scope, $http, $rootScope, testFactory)
{
....
}

Related

AngularJS TypeError is not a function

I have the following code in my service:
testApp.service('detailsService',['databaseService', 'loggedService', '$http', function(databaseService, loggedService, $http){
var details;
this.getDetails = function(name){
return $http({
method : "GET",
url : name
}).then(function(response) {
details= response.data;
console.log(response.data);
return response.data;
});
};
}]);
What i want to do is call this function in my controller when the page(view) is loaded.
testApp.controller('testController', ['$scope', '$location', 'databaseService','detailsService', '$routeParams', function($scope, $location, databaseService, $routeParams, detailsService){
$scope.details;
var selectedDetails = function(name){
detailsService.getDetails(name).then(function(data){
$scope.details= data;
});
};
selectedDetails(name);
}]);
I keep getting the error detailsService.getDetails is not a function.
I'm using the same function from the detailsService in another controller without any problems.
Does anybody know why i keep getting this error?
The error is expected as you are not injecting dependencies properly, You need to use the correct sequence.
testApp.controller('testController', ['$scope',
'$location',
'databaseService',
'detailsService',
'$routeParams',
function($scope, $location, databaseService, detailsService, $routeParams ){
instead of
testApp.controller('testController', ['$scope',
'$location',
'databaseService',
'detailsService',
'$routeParams',
function($scope, $location, databaseService, $routeParams, detailsService){
Note Both the string part and the function arguments need to match up 1:1.
remove the promise in the service.Just return the request. since you are catching the promise from the controller no need to use it in the service
testApp.service('detailsService', ['databaseService', 'loggedService', '$http', function(databaseService, loggedService, $http) {
var details;
this.getDetails = function(name) {
return $http({
method: "GET",
url: name
})
};
}]);
Also make sure the sequence is correct order when you are injecting services.
change this
testApp.controller('testController', ['$scope', '$location', 'databaseService', 'detailsService', '$routeParams', function($scope, $location, databaseService, $routeParams, detailsService )
to this
testApp.controller('testController', ['$scope', '$location', 'databaseService', 'detailsService', '$routeParams', function($scope, $location, databaseService, detailsService , $routeParams)
controller
testApp.controller('testController', ['$scope', '$location', 'databaseService', 'detailsService', '$routeParams', function($scope, $location, databaseService, detailsService , $routeParams) {
$scope.details;
var selectedDetails = function(name) {
detailsService.getDetails(name).then(function(data) {
$scope.details = data;
});
};
selectedDetails(name);
}]);
I got this error because I had added a callback method to a component, but the callback was not used by all the pages where that component was used:
<component [myCallbackFn]="fnNameToBindToFn">
component.ts:
public onClick() {
// some code
this.myCallbackFn();
}
Each time it was not used I got this error which was effectively a NullPointerException (from Java). So in the other uses of <component> in my website I had to add a check in the component before the callback to say:
if (undefined !== this.myCallbackFn) this.myCallbackFn();

Unable to call function as $rootScope is undefined

I am trying to call the function inside the controller 'Notification' when getNotification is called in the SelectNotificationCtlr. However when running this I get an Error stating that $rootScope is undefined on the line below console.log("log");. I have tried passing the $rootScope as a parameter in my getNotification function but still receive the same error.
Please see my code below, any advice or help would be really appreciated.
app.js
selectNotification.controller('selectNotificationCtlr', ['$scope', '$rootScope', 'notificationsService',
function($scope, $http, notificationsService, notificationService, $rootScope) {
$scope.getNotification = function() {
var id = $scope.selectedNotification;
notificationData = notificationsService.getNotifications();
console.log(notificationData);
console.log("log");
$rootScope.$emit("call", {});
}
}
]);
selectNotification.controller('Notification', ['$scope', '$rootScope',
function($scope, $rootScope) {
$rootScope.$on("call", function() {
$scope.parent(notificationService);
});
$scope.parent = function() {
console.log("log");
}
}
]);
Kind regards
CB
Your controller should have dependencies in the right order,
selectNotification.controller('selectNotificationCtlr', ['$scope', '$rootScope', 'notificationsService',
function($scope, $rootScope, notificationsService) {

Avoid a repeated scope variable in different controllers in AngularJS

I've got few controllers working with different templates:
curryApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'table_index.html',
controller: 'CurryListCtrl'
}).
when('/cities/:cityId/', {
templateUrl: 'template-total.html',
controller: 'CurryDetailCtrl'
}).
when('/cities/:cityId/mobile/', {
templateUrl: 'template-mobile.html',
controller: 'CurryMobileCtrl'
}).
when('/cities/:cityId/online/', {
templateUrl: 'template-online.html',
controller: 'CurryOnlineCtrl'
}).
All of theses controllers have $scope variable called cities
For example, the first one:
curryControllers.controller('CurryDesktopCtrl', ['$scope', '$routeParams', '$http', '$route',
function($scope, $routeParams, $http, $route) {
$scope.cityId = $routeParams.cityId;
$http.get('json/cities.json').success(function (data) {
$scope.cities = data;
...
The second one:
curryControllers.controller('CurryOnlineCtrl', ['$scope', '$routeParams', '$http', '$route',
function($scope, $routeParams, $http, $route) {
$scope.cityId = $routeParams.cityId;
$http.get('json/cities.json').success(function(data) {
$scope.cities = data;
...
Is it okay to have repeated $scope variables in different controllers?
How should I refactor the code in order to escape duplicates?
If cities are not going to change for every controller use services like below
Your service should look like below
app.service('myService',function($http,$q){
var cities=null;
this.getCities=function()
{
var deferred = $q.defer()
if(this.cities==null){
$http.get('json/cities.json')
.then((response) => {deferred.resolve(response);cities=response;})
.catch((error) => deferred.reject(error))
}
else { deferred.resolve(cities)}
return deferred.defer
})
});
Use the above service in the controller
app.controller('ctrl',function($scope,myService){
myService.getCities().then(function(data){ $scope.cities = data;})
})
You can create a factory:
.factory('citiesFactory', function($http) {
function getCities(){
// return promise from function
return $http.get("json/cities.json");
}
return {
getCities: getCities
}
});
then in your controller:
curryControllers.controller('CurryDesktopCtrl', ['$scope', '$routeParams', '$http', '$route', 'citiesFactory'
function($scope, $routeParams, $http, $route, citiesFactory) {
$scope.cityId = $routeParams.cityId;
citiesFactory.getCities().then(function(response){
$scope.cities = response.data;
});
...
You should do create a factory like this. Forgive the syntax, but you get the idea.
app.factory('Cities', function ($http) {
return {
'getData': function() {
$http.get('json/cities.json').success(function (data) {
return data;
}
.error(function(error){
return [];
}
}
};
}]);
and in your controller inject the factory and get the data
curryControllers.controller('CurryOnlineCtrl', ['$scope', '$routeParams', '$http', '$route', 'Cities'
function($scope, $routeParams, $http, $route) {
$scope.cityId = $routeParams.cityId;
$scope.cities = Cities.getData();
...
If the cities json is common for all the controllers.
One option would be to move the common object used across controllers into rootscope refer.
Other option would be to store the cities json in the service itself read here.

AngularJS - controller and factory - where am I going wrong at include/inject functions?

I'm new to Angular and cannot pinpoint where I am going wrong. I'm just trying to simply inject my factory into my controller, reference said: "Cannot read property 'validar' of undefined". I have two files, ServiceUtil.js where have a service and CentroCustoCtrl.js where I'm trying to use service's function.
The function at ServiceUtil.js:
(function () {
'use strict';
angular.module('Services', [])
.service('ValidarFormulario', [function () {
this.validar = function (form) {
var valido = true;
//code
}
return valido;
}
}]);
})();
And CentroCustoCtrl.js
(function () {
'use strict';
var app = angular.module("start", ['AxelSoft', 'ngLocalize',
'ngLocalize.Config', 'mvComponentes','Services'])
.value('localeConf', {
basePath: '../Scripts/Locales', ...
...
});
app.controller('CentroCustoCtrl', ['$scope', '$http', 'ValidarFormulario', function ($scope, $http, $rootScope, $timeout, ValidarFormulario) {
$scope.Salvar = function () {
if (ValidarFormulario.validar(document.getElementsByTagName('input'))) { ...// Cannot read property 'validar' of undefined
);
I tried with factory , but not worked too:
angular.module('Services', [])
.factory('ValidarFormulario', [function () {
return{
validar : function (form) {
var valido = true;
//code
}
}
return valido;
}
}
}]);
})();
Please, I appreciate any help you can provide.
The problem is you had wrong dependency sequence inside DI inline array, basically they are mismatching in number and their sequences
app.controller('CentroCustoCtrl', ['$scope', '$http', 'ValidarFormulario',
//removed $rootScope, $timeout which wasn't used.
function ($scope, $http, ValidarFormulario) {
OR either way you could just add the dependency inside array, if they are really gonna used inside controller like below
app.controller('CentroCustoCtrl', ['$scope','$http','$rootScope','$timeout','ValidarFormulario',
function ($scope, $http, $rootScope, $timeout, ValidarFormulario) {
Just change the below line of code
app.controller('CentroCustoCtrl', ['$scope', '$http', 'ValidarFormulario', function ($scope, $http, $rootScope, $timeout, ValidarFormulario) {
to
app.controller('CentroCustoCtrl', ['$scope', '$http', '$rootScope', '$timeout', 'ValidarFormulario', function ($scope, $http, $rootScope, $timeout, ValidarFormulario) {
This should work.
Well, also I've saw that your controller injections are wrong. You have:
App.controller('CentroCustoCtrl', ['$scope', '$http', 'ValidarFormulario', function ($scope, $http, $rootScope, $timeout, ValidarFormulario)
And you should have:
app.controller('CentroCustoCtrl', ['$scope', '$http', '$rootScope', '$timeout', 'ValidarFormulario', function ($scope, $http, $rootScope,$timeout, ValidarFormulario)
Injectors on "[ ]" must mach with function parameters.
When you set a module the syntax is:
angular.module('Services', [ here injections ])
But when you get a module to use it, syntax must be:
angular.module('Services')

Angularjs how to call a function of a controller from another controller

I am trying to split a big controller. The way to go would be through factories, but since I am changing the DOM I should do it through controllers.
Then, what I am trying to achieve is to call a function defined in Cntrl2 from Cntrl1.
The example
html
<body ng-app="app">
<div ng-controller='Cntrl1'>
{{message}}
</div>
</body>
js
var myModule = angular.module('app', []);
angular.module('app').controller('Cntrl1',
['$scope', '$q', '$timeout', 'Share_scope',
function ($scope, $q, $timeout, Share_scope) {
Share_scope.process();
$scope.message = 'started';
}]);
angular.module('app').controller('Cntrl2',
['$scope', '$q', '$timeout', 'Share_scope',
function ($scope, $q, $timeout, Share_scope) {
Share_scope.x = function() {
alert('done');
}
}]);
angular.module('app').factory('Share_scope',
['$window', '$q',
function($window, $q) {
var x;
return {
process: function() {
return x;
},
};
}]);
The demo http://jsfiddle.net/T8rgv/7/
What I would expect is to define "var x" of the factory as the function of Cntrl2, and then execute this function through the factory when I call it from Cntrl1.
So, how to make this work? Is this approach correct? Or should I just change the DOM from a factory?
Cheers,
Gerard
Not knowing where in relation Cntrl2 is to Cntrl1, I would use emit or broadcast somewhat like this. Note from past experience I don't think it's a good idea to use two or more different modules in the same page.
var myModule = angular.module('app', []);
angular.module('app').controller('Cntrl1',
['$scope', '$q', '$timeout', 'myFactory',
function ($scope, $q, $timeout, myFactory) {
$scope.$emit('messageEvt','started');
myFactory.process().then(function() {
$scope.$emit('messageEvt','ended');
});
}]);
angular.module('app').controller('Cntrl2',
['$scope', '$q', '$timeout', $rootScope,
function ($scope, $q, $timeout, $rootScope) {
$rootScope.$on('messageEvt',function(e,msg) {
$scope.message = msg;
}
}]);
angular.module('app').factory('myFactory',
['$window', '$q','$timeout',
function($window, $q,$timeout) {
var x;
return {
process: function() {
var deferObj = $q.defer();
$timeout(function() {
deferObj.resolve(x);
});
return deferObj.promise;
},
};
}]);
I think better way to do this is by having factory maintain the model and both controllers updating it when needed.
I updated the fiddle to http://jsfiddle.net/hh5Cy/2/
angular.module('app').factory('Share_scope',
['$window', '$q',
function($window, $q) {
var x;
return {
getProcess: function() {
return x;
},
setProcess: function(value){
x = value;
}
};
}]);
Please let me know if I understood you wrongly.

Categories

Resources