How can I inject multiple services into one controller? - javascript

I have an EmailAccountsController and I need to inject 'Hosting' and 'EmailAccount' services into it. Here is my code:
hostingsModule.controller('EmailAccountsCtrl', ['$scope', 'Hosting', 'EmailAccount', function ($scope, Hosting, EmailAccount) {
var hostingId = 1
$scope.hosting = Hosting.find(hostingId);
$scope.emailAccounts = EmailAccount.all(hostingId)
}]);
The error message is TypeError: Cannot call method 'all' of undefined
When I inject only one service into the same controller, everything works. Is there a way how to inject multiple services into one controller?
EDIT: I've tried to put all the relevant code into one file. It' looks like this:
hostingsModule.factory('Hosting', ['$http', function($http) {
var Hosting = function(data) {
angular.extend(this, data);
};
Hosting.all = function() {
return $http.get('<%= api_url %>/hostings.json').then(function(response) {
return response.data;
});
};
Hosting.find = function(id) {
return $http.get('<%= api_url %>/hostings/' + id + '.json').then(function(response) {
return response.data;
});
}
return Hosting;
}]);
hostingsModule.factory('EmailAccount', ['$http', function($http) {
var EmailAccount = function(data) {
angular.extend(this, data);
};
EmailAccount.all = function(hostingId) {
return $http.get('<%= api_url %>/hostings/' + hostingId + '/email-accounts.json').then(function(response) {
return response.data;
});
};
EmailAccount.find = function(id) {
return $http.get('<%= api_url %>/hostings/' + id + '.json').then(function(response) {
return response.data;
});
};
}]);
hostingsModule.controller('EmailAccountsCtrl', ['$scope', 'Hosting', 'EmailAccount', function($scope, Hosting, EmailAccount) {
var hostingId = 1;
$scope.hosting = Hosting.find(hostingId);
$scope.emailAccounts = EmailAccount.all(hostingId)
console.log($scope.hosting);
console.log($scope.emailAccounts);
}]);

Scope issue. You need to return EmailAccount since it is initialized inside the closure.
You need to add return EmailAccount; like what you did for Hosting.
Or try this code:
hostingsModule.factory('EmailAccount', ['$http', function ($http) {
var service = {
all: function (hostingId) {
return $http.get('<%= api_url %>/hostings/' + hostingId + '/email-accounts.json').then(function (response) {
return response.data;
});
},
find: function (id) {
return $http.get('<%= api_url %>/hostings/' + id + '.json').then(function (response) {
return response.data;
});
}
}
return service;
}]);

Related

How to pass $scope to factory

I'm trying to pass a scope to a factory and use it in the controller where the function should be invoked, but it just doesn't work.
var myApp = angular.module('mainApp', []);
myApp.factory("UserService", function ($http) {
var users = ["xxxxx", "yyyyy", "zzzzz"];
return {
all: function () {
return users;
console.log( users );
},
first: function () {
return users[1];
},
checkUser: function(elUrl, classHide, classShow){
$http.post(elUrl)
.success(function (data, status, headers, config) {
if (!data.isMember) {
el = classHide //should be when invoking: $scope.mailexist = classHide;
$('form').submit();
} else {
el = classShow //should be when invoking: $scope.mailexist = classShow;
return false;
}
}).error(function (data, status, header, config) {
//$scope.ResponseDetails = "Data: " + data +
"<hr />status: " + status +
"<hr />headers: " + header +
"<hr />config: " + config;
});
}
};
});
myApp.controller('mainCtrl', ['$scope', '$http', 'UserService', function ($scope, $http, UserService) {
UserService.checkUser( 'inc/memberSearch.jsp?user.Email=' + $scope.umail + '&group.PK=' + angular.element('.grp').val(),
$scope.mailexist,
'mail-exist-hide',
'mail-exist-show');
}]);
mailexists is the ng-class for the text element in the HTML which should be shown or hidden depending on the server response:
<p ng-class="mailexist">Text Text text Text</p>
The function in the controller is being invoked but The Text doesn't appear. If I add the $scope in the factory, then I get $scope is not defined which is true.
But $scope can't be injected in a factory/service.
Any ideas?
You should handle the success or error in the controller , just return the response
checkUser: function(elUrl, classHide, classShow){
return $http.post(elUrl)
}
handle in the controller
UserService.checkUser( 'inc/memberSearch.jsp?user.Email=' + $scope.umail + '&group.PK=' + angular.element('.grp').val(),
$scope.mailexist,
'mail-exist-hide',
'mail-exist-show').then(function(){
if (!response.data.isMember) {
$scope.mailexits = 'mail-exist-hide';
$('form').submit();
} else {
$scope.mailexits = 'mail-exist-show';
return false;
}
}, function(response){
$scope.ResponseDetails = "Data: " + response.data;
});}]);
factory in MVC represents model and shouldn't be coupled with view - thing you are trying to achieve should be handled by controller
something like this should be ok:
var myApp = angular.module('mainApp', []);
myApp.factory("UserService", function ($http) {
var users = ["xxxxx", "yyyyy", "zzzzz"];
return {
all: function () {
return users;
console.log( users );
},
first: function () {
return users[1];
},
checkUser: function(elUrl, classHide, classShow){
return $http.post(elUrl);
}
};
});
myApp.controller('mainCtrl', ['$scope', '$http', 'UserService', function ($scope, $http, UserService) {
UserService.checkUser( 'inc/memberSearch.jsp?user.Email=' + $scope.umail + '&group.PK=' + angular.element('.grp').val(),
$scope.mailexist,
'mail-exist-hide',
'mail-exist-show').then(function(){
// on success
}, function(){
// on error
});
}]);
Send $scope as parameter to factory like
UserService.checkUser($scope,param1,..);
Than use this in factory
checkUser: function(scope,p1,...){
now use this scope in factory :) hope this will help

Send data through a POST request from Angular factory

I have this in the controller
angular.module('myApp')
.controller('TaskController', function ($scope, TaskFactory) {
$scope.addTodo = function () {
$scope.todos.push({text : $scope.formTodoText});
$scope.formTodoText = '';
};
});
and this in the factory
angular.module('myApp')
.factory('TaskFactory', function ($q, $http) {
var sendTasks = function(params) {
var defer = $q.defer();
console.log(1, params);
$http.post('http://localhost:3000/task/save', params)
.success(function(data) {
console.log(2);
console.log('data', data);
})
.error(function(err) {
defer.reject(err);
});
return defer.promise;
}
return {
sendTask: function(taskData) {
console.log('taskData', taskData);
return sendTasks('/task/save', {
taskData : taskData
})
}
}
});
all I need is to know, how to send the data from the controller to the factory in order to do the POST to the specified route ?
You just need to call the function/method inside factory with the required params.
angular.module('myApp')
.controller('TaskController', function ($scope, TaskFactory) {
$scope.addTodo = function () {
$scope.todos.push({text : $scope.formTodoText});
TaskFactory.sendTask({data : $scope.formTodoText})
$scope.formTodoText = '';
};
});
You can follow Dan Wahlin blog post.
Controller:
angular.module('customersApp')
.controller('customersController', ['$scope', 'dataFactory', function ($scope, dataFactory) {
$scope.status;
dataFactory.updateCustomer(cust)
.success(function () {
$scope.status = 'Updated Customer! Refreshing customer list.';
})
.error(function (error) {
$scope.status = 'Unable to update customer: ' + error.message;
});
}
Factory:
angular.module('customersApp')
.factory('dataFactory', ['$http', function($http) {
var urlBase = '/api/customers';
dataFactory.updateCustomer = function (cust) {
return $http.put(urlBase + '/' + cust.ID, cust)
};
}
Hope that solve your problem.
You can call the function directly on the TaskFactory that you pass into the controller as a dependency.
I've cleaned up your code a bit and created a plunk for you here:
And here's the code:
Controller
(function(angular) {
// Initialise our app
angular.module('myApp', [])
.controller('TaskController', function($scope, TaskFactory) {
// Initialise our variables
$scope.todos = [];
$scope.formTodoText = '';
$scope.addTodo = function() {
// Add an object to our array with a 'text' property
$scope.todos.push({
text: $scope.formTodoText
});
// Clear the input
$scope.formTodoText = '';
// Call function to send all tasks to our endpoint
$scope.sendTodos = function(){
TaskFactory.sendTasks($scope.todos);
}
};
});
})(angular);
Factory
(function(angular) {
angular.module('myApp')
.factory('TaskFactory', function($q, $http) {
var sendTasks = function(params) {
var defer = $q.defer();
$http.post('http://localhost:3000/task/save', params)
.success(function(data) {
console.log('data: ' + data);
})
.error(function(err) {
defer.reject(err);
});
return defer.promise;
}
return {
sendTasks: sendTasks
}
});
})(angular);

$scope is undefined inside $http call

My angular code
angular.module('MyApp').
controller('ProductController', function ($scope, DropDownService) {
$scope.Product = {};
$scope.ProductCategoryList = null;
DropDownService.GetCategory().then(function (d)
{
$scope.ProductCategoryList = d.data;
});
}).
factory('DropDownService', function ($http) {
var fac = {};
fac.GetCategory = function() {
return $http.get('/Product/GetAllCategory');
};
return fac;
});
my server side
public JsonResult GetAllCategory()
{
//List<tblCategory> categories = new List<tblCategory>();
try
{
using(CurtainHomesDBEntities dc = new CurtainHomesDBEntities())
{
var categories = dc.tblCategory.Select(a => new { a.Id, a.CatagoryName }).ToList();
return Json(new { data = categories, success = true }, JsonRequestBehavior.AllowGet);
}
}
catch(Exception ex)
{
return Json(ex);
}
}
I did same way many times. but throwing js error ReferenceError: $scope is not defined when assigning value to $scope.ProductCategoryList after $http request. What is the problem here? I tried many way but couldn't find out.
Even I tried in this way
angular.module('MyApp').
controller('ProductController', function ($scope, $http) {
$scope.Product = {};
$scope.LoadCategory = function () {
$scope.categoryList = null;
$http.get('/Product/GetAllCategory/')
.success(function (data) {
$scope.categoryList = data.data;
})
.error(function (XMLHttpRequest, textStatus, errorThrown) {
toastr.error(XMLHttpRequest + ": " + textStatus + ": " + errorThrown, 'Error!!!');
})
};
});
Same problem. $scope is not defined
You need to inject $scope as well as your service
angularModule.controller("ProductController", ["$scope","$http", 'DropDownService', function ($scope, $http, DropDownService) {
$scope.Product = {};
$scope.ProductCategoryList = null;
DropDownService.GetCategory().then(function (d)
{
$scope.ProductCategoryList = d.data;
});
}]);
Inject the service in your controller,
angularModule.controller("ProductController", ['$scope','$http', 'DropDownService', function ($scope, $http, DropDownService) {
$scope.Product = {};
$scope.ProductCategoryList = null;
DropDownService.GetCategory().then(function (d)
{
$scope.ProductCategoryList = d.data;
});
})

How to test a controller function calling a private function that in turn calls a asynchronous function in angularjs

[plunkr][1]http://plnkr.co/edit/Jk1Rp3nEgUQTmDOs3xBl?p=preview
My current code is structured as below.
angular.module("app",[])
.service("dataService",function($http){
this.get = function (url) {
return $http.get(url);
};
})
.service("mainService",function(dataService){
this.getData = function(pattern){
return dataService.get(pattern+"/abc");
}
})
.controller("mainController",function($scope,mainService){
$scope.refreshData = function(pattern){
loadData(pattern);
}
function loadData(pattern){
mainService.getData(pattern)
.success(function(data){
console.log(data);
})
.error(function(error){
console.log(error);
})
}
})
I have been trying to make sense of how to test it by reading blogs but each blog has either a different approach or the blog is 2-3 years old. I would like to know how do I test the controller?
Should I test each function? If yes, then how should I test the private function? Is using the private function a good idea or should I just add the private function code to the scoped function?
Also is there any better way to do write this function?
Most important part where we are going to create stub:
beforeEach(function() {
var $httpResponse = {
success: function() {
return $httpResponse;
},
error: function() {
return $httpResponse;
}
};
var _stubMainService_ = {
getData: jasmine.createSpy('getData').and.returnValue($httpResponse)
};
angular.module('app')
.value('mainService', _stubMainService_);
});
and test that uses it:
it('rereshes data', function() {
var pattern = 'abcde';
scope.refreshData(pattern);
expect(mainService.getData).toHaveBeenCalledWith(pattern);
});
angular.module("app", [])
.service("dataService", function($http) {
this.get = function(url) {
return $http.get(url);
};
})
.service("mainService", function(dataService) {
this.getData = function(pattern) {
return dataService.get(pattern + "/abc");
}
})
.controller("mainController", function($scope, mainService) {
$scope.refreshData = function(pattern) {
loadData(pattern);
}
function loadData(pattern) {
mainService.getData(pattern)
.success(function(data) {
console.log(data);
}).error(function(error) {
console.log(error);
})
}
})
describe('mainController()', function() {
var scope, controller, mainService, $q;
beforeEach(module('app'));
beforeEach(function() {
var $httpResponse = {
success: function() {
return $httpResponse;
},
error: function() {
return $httpResponse;
}
};
var _stubMainService_ = {
getData: jasmine.createSpy('getData').and.returnValue($httpResponse)
};
angular.module('app')
.value('mainService', _stubMainService_);
});
beforeEach(inject(function($controller, $rootScope, _mainService_) {
scope = $rootScope.$new();
controller = $controller('mainController', {
$scope: scope
});
mainService = _mainService_;
}));
it('rereshes data', function() {
var pattern = 'abcde';
scope.refreshData(pattern);
expect(mainService.getData).toHaveBeenCalledWith(pattern);
});
})
<link href="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine.css" rel="stylesheet" />
<script src="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine-2.0.3-concated.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-mocks.js"></script>

Passing argument to a factory for a service

I have this HTML:
<div class='container-fluid' ng-controller="TypeaheadCtrl">
<p></p>
<b>Selected User</b>
Enter a name: <input type="text" ng-model="selected" typeahead="user as (user.first + ' ' + user.last) for user in users | filter:$viewValue" />
</div>
this controller:
app.controller('TypeaheadCtrl', ['$scope', 'getUser',function($scope, getUser) {
$scope.selected = "";
getUser.success(function(data) {
$scope.users = data;
});
}]);
and this service:
app.factory('getUser', ['$http', function($http) {
return $http.get('https://myUrl?param=Foo')
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}]);
How can I pass an argument to the service to make the value of param in URL dynamic?
The easiest way with minimal change is to change your factory so that it returns a function
app.factory('getUser', ['$http', function($http) {
var httpReq = function(param){
return $http.get('https://myUrl?' + param + '=Foo')
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}
return httpReq;
}]);
Now you can pass a value into your factory
app.controller('TypeaheadCtrl', ['$scope', 'getUser',function($scope, getUser) {
$scope.selected = "";
getUser('paramValue').success(function(data) {
$scope.users = data;
});
}]);
A factory creates an object and returns it as the publically available operations. So, you can create and return an object that wraps the HTTP call:
app.factory('getUser', ['$http', function($http) {
function myInternal(arg1) {
return $http.get('https://myUrl?param=' + arg1)
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}
return {
makeMyCall: function(arg1) {
return myInternal(arg1);
}
};
}]);
Then from the controller you can invoke the getUser.makeMyCall function passing in the argument.
BTW, if you are not adding anything to the promise chain that there is no need to handle the success and error function in the factory:
function myInternal(arg1) {
return $http.get('https://myUrl?param=' + arg1);
}
return {
makeMyCall: function(arg1) {
return myInternal(arg1);
}
};
app.controller('TypeaheadCtrl', ['$scope', 'getUser',function($scope, getUser) {
$scope.selected = "";
getUser('Foo').success(function(data) {
$scope.users = data;
});
}]);
app.factory('getUser', ['$http', function($http) {
return function(myParam) {
return $http.get('https://myUrl', {param:{param:myParam}});
};
}]);

Categories

Resources