I am calling a service method in my controller to return an object. I struggled a lot to figure out the exact implementation difference between a service and a factory.
According to what I learned service instantiates with new and returns this to the calling controller.
I am trying to accomplish the same here..calling a service function in controller and storing the returned object in controller's $scope.user variable as follows:
controller:
app.controller('LoginFormController',['$log','$scope','userAngService','userBean',function($log,$scope,userAngService,userBean){
$scope.user = {};
$scope.login = function(val){
userAngService.login(val);
$scope.user = userAngService.user; //accessing service's user variable
//$scope.user = userAngService.user;
console.log($scope.user); //empty object being logged in console
};
}]);
service:
app.service('userAngService',['$http','$log','$rootScope','$location',function($http,$log,$rootScope,$location){
this.user = {};
this.login = function(val){
console.log('from angular service');
$http({
method: 'GET',
url: 'http://localhost:7070/messenger/webapi/messages'
}).success(function(data){
user = data;
console.log(user); //successfully logging "user" in console
});
};
return this;
}]);
Above in the service the login function(val) is changing the user variable defined in the service itself.
I can make the function to return this.user but still am getting the same result.
What changes should I make here?
And here is what I am getting in console:
You are calling $http service internally on your userAngService service.
Its a asynchronous service call so, just return the promise object to the controller and then assign values to $scope.user.
Controller
app.controller('LoginFormController', ['$log','$scope','userAngService','userBean',function($log,$scope,userAngService,userBean){
$scope.login = function(val){
userAngService.login(val).then(function(data){
$scope.user = data;
console.log($scope.user);
});
};
}]);
Service
app.service('userAngService',['$http','$log','$rootScope','$location',function($http,$log,$rootScope,$location){
this.user = {};
this.login = function(val){
console.log('from angular service');
return $http({
method: 'GET',
url: 'http://localhost:7070/messenger/webapi/messages'
});
};
}]);
Service
app.service('userAngService',['$http','$log','$rootScope','$location',function($http,$log,$rootScope,$location){
this.user = {};
this.login = function(val){
console.log('from angular service');
// here you are returning Promise
return $http({
method: 'GET',
url: 'http://localhost:7070/messenger/webapi/messages'
}).success(function(data){
user = data;
console.log(user); //successfully logging "user" in console
return user;
});
};
}]);
The first thing is, you don't need to return anything from service. This is the one of the difference from factory. In factory you need to return an object, but no need to return any object in service
controller
app.controller('LoginFormController',['$log','$scope','userAngService','userBean',function($log,$scope,userAngService,userBean){
$scope.user = {};
$scope.login = function(val){
userAngService.login(val).then(userName){
$scope.user = userName;
console.log($scope.user);
};
};
}]);
Your controller is logging a blank object which is correct since it is a blank object. Can you try this?
app.service('userAngService',['$http','$log','$rootScope','$location',function($http,$log,$rootScope,$location){
var vc = this;
vc.user = {};
vc.login = function(val){
console.log('from angular service');
$http({
method: 'GET',
url: 'http://localhost:7070/messenger/webapi/messages'
}).success(function(data){
vc.user = data;
console.log(user); //successfully logging "user" in console
});
};
}]);
OR this...
app.service('userAngService',['$http','$log','$rootScope','$location',function($http,$log,$rootScope,$location){
var vc = this;
vc.user = {};
vc.login = function(val){
console.log('from angular service');
$http({
method: 'GET',
url: 'http://localhost:7070/messenger/webapi/messages'
}).success(function(data){
$rootScope.$apply(function(){vc.user = data;});
console.log(user); //successfully logging "user" in console
});
};
}]);
Your Service needs to return an abject. This should work:
app.service('userAngService',['$http','$log','$rootScope','$location',function($http,$log,$rootScope,$location){
this.user = {};
this.login = function(val){
console.log('from angular service');
$http({
method: 'GET',
url: 'http://localhost:7070/messenger/webapi/messages'
}).success(function(data){
user = data;
console.log(user); //successfully logging "user" in console
});
};
return this;
}]);
or if you want to use private and public funtions (module pattern) in javascript. Do:
app.service('userAngService',['$http','$log','$rootScope','$location',function($http,$log,$rootScope,$location){
var user = {};
var handleRequestData = function(data){
user = data;
console.log(user); //successfully logging "user" in console
};
var login = function(val){
console.log('from angular service');
$http({
method: 'GET',
url: 'http://localhost:7070/messenger/webapi/messages'
}).success(handleRequestData);
};
/* while you returning just the login function, user and handleRequestData stay private */
return {
login: login
};
}]);
You have to user promise in order to get data from a service via HTTP request because what happened when your http request give response back to controller there is no handler to receive it.
Controller should be :
app.controller('LoginFormController',['$log','$scope','userAngService','userBean',function($log,$scope,userAngService,userBean){
$scope.user = {};
$scope.login = function(val){
userAngService.login(val).then(function(res){
$scope.user = res;
//$scope.user = userAngService.user;
console.log($scope.user);
console.log(userAngService.user);
});
};
}]);
Service should be :
app.service('userAngService',['$http','$log','$rootScope','$location', '$q',function($http,$log,$rootScope,$location,$q){
this.user = {};
this.login = function(val){
var deferred = $q.defer();
var promise = deferred.promise;
console.log('from angular service');
$http({
method: 'GET',
url: 'http://localhost:7070/messenger/webapi/messages'
}).success(function(data){
user = data;
console.log(user); //successfully logging "user" in console
deferred.resolve(user);
});
return promise;
};
return this;
}]);
I have not tested this code and i think it will work for you but if not the case please let me know.
Related
I am writing a program to connect to a rest api... But factory function doesnt work ... While everything seems to be correct
factory:
app.factory('publisherService', ['$http', function($http){
var services = {};
var userInfo = {};
services.getUser = function()
{
$http({method: 'GET', url: '/phoenix/publisher/user'}).success(function(data){
userInfo = data;
});
return userInfo;
};
return services;
}]);
controller:
app.controller('publisher', ['$scope','publisherService', '$http',function($scope, publisherService,$http)
{
$scope.publisher = {};
$scope.publisher = publisherService.getUser();
}]);
When program runs $scope.publisher returns {}
But the following code runs well
app.controller('publisher', ['$scope','publisherService', '$http',function($scope, publisherService,$http)
{
$scope.publisher = {};
$http( {method: 'GET', url: '/phoenix/publisher/user'} ).success(function(data){
$scope.publisher = data;
});
}]);
The problem was resolved using $q...
$q is well explained in this article.
The service should return a promise:
app.factory('publisherService', ['$http', function($http){
var services = {};
var userInfo = {};
services.getUser = function()
{
var promise = $http({method: 'GET', url: '/phoenix/publisher/user'});
return promise;
};
return services;
}]);
Then the controller should use the promise:
app.controller('publisher', function($scope, publisherService,$http)
{
var promise = publisherService.getUser();
promise.then( function onSuccess(result) {
$scope.publisher = result.data;
});
});
The reason that the service was returning an empty object was that the function given as an argument to the .success method is held by the $q service until results from the XHR return. The $q stores the function and only invokes it when results are available. The empty object was returned to the service function before the XHR completed.
Have the service function return the XHR promise, and then have the onSuccess function put the results on $scope.
here is my javascript code
$scope.addUser = function () {
debugger;
url = baseURL + "AddUser";
$scope.objUser = [];
$scope.objUser.push( {
"ID": '0',
"UserName": $scope.txtUserName,
"Password": $scope.txtPassword,
"Role":"Non-Admin"
});
$http.post(url,$scope.objUser[0])
.success(function (data) {
debugger;
alert("S");
window.location = "../View/Login.html";
}).error(function () {
debugger;
alert("e");
});
}
here is my server method code
[HttpPost]
public int AddUser(UserModel user)
{
//_entity.Configuration.ProxyCreationEnabled = false;
tblUser objUser = new tblUser();
objUser.UserName = user.UserName;
objUser.Password = user.Password;
objUser.Role = user.Role;
_entity.tblUsers.Add(objUser);
_entity.SaveChanges();
return objUser.ID;
}
You can use promises to get the response. this can be inside into a service and call it whenever you want to use it.
this.addUser = function (obj) {
var datosRecu = null;
var deferred = $q.defer();
var uri = baseUrl + 'addUser';
$http({
url: uri,
method: 'post',
data: angular.toJson(obj)
}).then(function successCallback(response) {
datosRecu = response;
deferred.resolve(datosRecu);
}, function errorCallback(response) {
datosRecu = response;
deferred.resolve(datosRecu);
});
return deferred.promise;
};
Also .error and .success are deprecated.
PD: the parameter data: inside the $http correspond to the body. if you want to send parameters you should use params:{}
EDIT:
Here i leave you a link how promises work. Angular promises
Basically this helps to process data asynchronously
the example above can be used inside a service like this
myApp.service('myService', function($q, $http){
// here your services....
});
the service can be injected inside to any controller to provide the data that what you want, inside of your functions
myApp.controller('myController', function($scope, myService){
$scope.list = function(){
$promise = myService.getAll(); // this will be the name of your function inside your servive
$promise.then(function(data){
console.log(data); //here you can se your promise with data like status and messages from the server.
});
};
});
Hope it helps.
I've been trying to implement this easy feature in Angular, but without no success.
I have two controllers and one service. The service provides a shared methods to retrieve if user is logged in or not;
app.factory("shared",["$rootScope",function($rootScope){
var data = {};
data.val = false;
data.get = function() {
return data.val;
},
data.set = function(val) {
data.val = val;
};
return data;
}]);
Then I have a controller attached to login/logout bar where login and logout links should be changed with the help of ng-show and ng-hide. Here is a html code for this:
<ul class="reg" ng-controller="mainCntr">
<li ng-hide="shared.get()"> Signup </li>
<li ng-hide="shared.get()">Login</li>
<li ng-show="shared.get()">Logout</li>
</ul>
And mainCntr attached to this:
app.controller("mainCntr,["$scope","shared","$rootScope",function($scope,shared, $rootScope){
$scope.$watch("shared.get()",function(newval){
console.log(newval);
},true);
}]);
And lastly, I have login controller for login form rendered into when we are on /login page. I should notice that the above HTML for login/signup links is always on index.html page. So, loginCntr is below:
app.controller("loginCntr",["$scope","$http", "$window","$rootScope", "$location","shared",function($scope,$http, $window, $rootScope,$location,shared){
$scope.login = "";
$scope.password = "";
$scope.response = "";
$scope.loggedin = false;
$scope.submit = function(isValid) {
if (isValid) {
$http({
method: "POST",
url: "/authenticate",
data: $.param({login:$scope.login,password:$scope.password}),
headers: {"Content-Type": "application/x-www-form-urlencoded"}
}).success(function(data,status,headers,config){
$window.sessionStorage.token = data.token;
console.log($window.sessionStorage.token);
$scope.response = "You logged in successfully";
shared.set(true); /////// Here I set shared valued to true when the user is logged
}).error(function(data,status,error,config){
delete $window.sessionStorage.token;
$scope.response = data.response;
});
};
};
}]);
So, that's it, but it doesn't work. Being new to Angular, it is hard time for me to figure out what is wrong. May be it's because "shared" value is set in asynchronyous callback and thus never read, because the login section has been already loaded?
why you not try $emit event listener.
like :
///****mainCntr
app.controller("mainCntr,["$scope","shared","$rootScope",function($scope,shared, $rootScope){
$scope.$on("loginEvent", function($event, args){
alert(args.msg);
});//Listen $emit Event
}]);
///****loginCntr
app.controller("loginCntr",["$scope","$http", "$window","$rootScope", "$location","shared",function($scope,$http, $window, $rootScope,$location,shared){
$scope.login = "";
$scope.password = "";
$scope.response = "";
$scope.loggedin = false;
$scope.submit = function(isValid) {
if (isValid) {
$http({
method: "POST",
url: "/authenticate",
data: $.param({login:$scope.login,password:$scope.password}),
headers: {"Content-Type": "application/x-www-form-urlencoded"}
}).success(function(data,status,headers,config){
$window.sessionStorage.token = data.token;
console.log($window.sessionStorage.token);
$scope.response = "You logged in successfully";
$scope.$emit("loginEvent", {msg : "Login Successful..."}) /////// Emit an event
}).error(function(data,status,error,config){
delete $window.sessionStorage.token;
$scope.response = data.response;
});
};
};
}]);
I get a problem in AngularJS when getting data from JSON using service factory ($resource)
services.factory('GetCustomerByEmailFactory', function ($resource) {
return $resource(url + '/customerService/getCustomerByMail?email=:email', {}, {
getByMail: { method: 'GET', params: {email: '#email'} }
});
});
this service works well
but the controller part doesn't work
app.controller('CustomerCreationCtrl', ['$scope','PostCustomerFactory', '$location','Subscription','AddNotificationFactory','$routeParams','GetCustomerByEmailFactory',
function ($scope, PostCustomerFactory, $location,Subscription,AddNotificationFactory,$routeParams,GetCustomerByEmailFactory) {
$scope.customer ={};
$scope.not ={};
$scope.aftercustomer ={};
$scope.createNewCustomer = function(){
Number($scope.customer.PhoneNumber);
$scope.customer.SubscriptionDate = "1990-02-23T00:00:00";
$scope.customer.ManagerIdCustomer=1;
PostCustomerFactory.create($scope.customer);
var customer = GetCustomerByEmailFactory.getByMail({email:$scope.customer.Email}).$promise;
customer.then(function (responce){
$scope.aftercustomer = responce;
window.alert($scope.aftercustomer.Id);
$scope.not.CustomerId = $scope.aftercustomer.Id;
$scope.not.ManagerId = $routeParams.id;
AddNotificationFactory.create($scope.not);
});
$location.path("/login");
};
}]);
the window.alert show me an undefined value so that it doesn't get the data
Okay, I have this function in a service:
wikiServices = angular.module('wikiServices', []);
wikiServices.factory('newsService', function($http, $q){
var chosenNewsStory = "";
var getNewsStory = function(news_id, callback){
var deferred = $q.defer();
$http({
method: "GET",
url: "news/article/" + news_id
})
.success(function(newsStory){
deferred.resolve(newsStory);
console.log("RESOLVED " + newsStory);
});
return deferred.promise;
});
Controller 1:
wikiControllers = angular.module('wikiControllers', []);
wikiControllers.controller('ctrl1', ['$scope', 'newsService',
function($scope, newsService){
$scope.getNewsStory = newsService.getNewsStory(function(input){
newsService.getNewsStory(news_id);
};
});
Controller 2:
wikiControllers = angular.module('wikiControllers', []);
wikiControllers.controller('ctrl1', ['$scope', 'newsService',
$scope.watch('newsService.chosenNewsStory', function(newVal){
console.log(newVal);
});
});
Now, I have tried setting "chosenNewsStory" in the service a lot of places buyt I think I'm missing a key part of the whole JS-"experience".
I'm having trouble setting "var chosenNewsStory" in the service to the newsStory fetched from the server. How can I do this?
Thanks.
You should define get and set methods for the variable that is being shared, and return these as well. I would format your service like so:
wikiServices.factory('newsService', function($http, $q){
var chosenNewsStory = "";
return {
getNewsStory: function(news_id, callback){
var deferred = $q.defer();
$http({
method: "GET",
url: "news/article/" + news_id
}).success(function(newsStory){
deferred.resolve(newsStory);
console.log("RESOLVED " + newsStory);
});
return deferred.promise;
},
getNews: function() {
return chosenNewsStory;
},
setNews: function(story) {
chosenNewsStory = story;
}
}
});
Now you will be able to watch newsService.getNews() and set it with newsService.setNews(news)