I'm trying to write an Angular service and it seems like there is something missing. My problem is its not returning any value to my Angular controller
getPrepTimes() method is not returning the http data
But when I check the network (via Chrome dev tools) it will correctly call the external api and return a json object as a response
#my service
'use strict';
angular.module('recipeapp')
.service('prepTimeService',['$http', function($http){
this.prepTime = getPrepTimes();
function getPrepTimes(){
$http({
url: '/prep_times/index.json',
method: 'GET'
})
.success(function (data, status, header, config){
return data;
});
};
}
]);
#controller
'use strict';
angular.module('recipeapp')
.controller('recipeCtrl', ['$scope', 'prepTimeService', function($scope, prepTimeService){
$scope.prep_time = prepTimeService.prepTime;
}]);
When I checked the method getPrepTimes() with returning a string it works. What could be missing here?
A couple things are wrong with the above. You assign this.prepTime to getPrepTimes(). The () there will invoke getPrepTimes immediately, and not when you actually call it! You also need to utilize callbacks to get your data back and use it:
angular.module('recipeapp').service('prepTimeService',['$http', function($http){
this.prepTime = getPrepTimes;
function getPrepTimes(callback) {
$http({
url: '/prep_times/index.json',
method: 'GET'
}).success(function (data, status, header, config){
callback(data);
});
};
}]);
And now use it like so:
prepTimeService.prepTime(function(data) {
$scope.prep_time = data;
});
Calls to the $http service are async, which means you need to return a promise (and not a value):
this.prepTime = function() {
return $http({
url: '/prep_times/index.json',
method: 'GET'
});
};
And on the controller:
angular.module('recipeapp')
.controller('recipeCtrl', ['$scope', 'prepTimeService', function($scope, prepTimeService){
$scope.prep_time = prepTimeService.prepTime()
.success(function (data, status, header, config){
$scope.someVar = data;
});
}]);
Wrap answer with promise:
var self = this;
var deferred = $q.defer();
self.getPrepTimes = function() {
$http({
url: '/prep_times/index.json',
method: 'GET'
})
.success(function(data, status, headers, config) {
if (data.error === undefined) {
deferred.resolve(data);
} else {
if (data.error !== undefined) {
} else {
deferred.reject(data);
}
}
}).error(function(data, status, headers, config) {
deferred.reject(data);
});
return deferred.promise;
};
In controller call it:
prepTimeService.getPrepTimes().then(function(result) {
$scope.prep_time = result;
},
function(error) {
// show alert
});
Related
I'm starting to read about services in Angular and confused as to how to use them with $http.
I currently use $http to fetch data from my REST API like the code below;
$scope.getRestaurant = function () {
var baseUrl = 'http://api.example.com/web/restaurant/details/' + $scope.id;
$http({
method: 'get',
url: baseUrl,
headers: {'Content-Type': 'application/json'}
}).
success (function(data, status, headers, config){
if(data && !angular.isUndefined(data) ){
$scope.restaurant = data;
} else {
$scope.restaurant = [];
}
}).
error(function(data, status, headers, config) {
//$scope.messageFailure(data.message);
});
}
$scope.id is a value on my controller how can I turn this function into service and then access the data returned in my controller?
This is how you can create a factory or service that has a function which takes an argument, you can then pass $scope.id in your controller to that function.
So to start, create a factory:
app.factory('myFactory', function($http) {
var factory = {};
var _myfunction = function(id)
{
return $http.get('http://api.example.com/web/restaurant/details/'+id);
}
factory.myFunction = _myfunction;
return factory;
});
and then in your controller, you will have:
app.controller('myCtrl', function('myFactory'){
var x = $scope.id;
$scope.getRestaurant = function (x) {
myFactory.myFunction(x).success(function(data, status, headers, config){
//whatever...
}).error(function(){
// whatever....
})
};
});
Of course it's just a general idea, you need to tweak it to meet your exact needs.
You have to inject the service into the controller and talk to it through there.
Quick example:
Your service
app.service '$restaurants', ['$http', '$q', ($http, $q) ->
fetch: (id) ->
deferred = $q.defer()
config =
url: "//api.example.com/web/restaurant/details/#{id}"
method: 'GET'
headers: 'Content-Type': 'application/json'
dataType: 'json'
x = $http config
x.error (data, status) -> deferred reject data, status
x.success (response, status, headers, config) ->
deferred.resolve response
deferred.promise
Controller injects the service
app.controller 'GodClass', ['$restaurants', ($restaurants) ->
$scope.id = 1
$restaurants.fetch($scope.id).then (response) ->
console.log response
Very much simplified but it'll get you the results based on the ID that you pass to the service.
I am using angularjs and cordova tool for creating application.
I have created service, which contains code for calling APIs. and in that I want to return response to my angular controller.
My code is,
Service,
JodoModule.factory('commonServices', function ($http, $q, $rootScope) {
return {
getServiceData: function (url) {
$rootScope.loading = true;
var deferred = $q.defer();
var req = {
method: 'GET',
url: url
}
$http(req).success(function (data) {
alert("data in service = " + JSON.stringify(data.Data));
deferred.resolve(data);
}).error(function (data, status, headers, config) {
deferred.reject(status);
});
return deferred.promise;
}
};
});
My controller is,
commonServices.getServiceData("My url").
success(function (data, status, headers, config) {
alert(data);
}).
error(function (data, status, headers, config) {
alert("Got error");
});
In above code, in service, its showing elert message for JSON.stringify(data.Data)); in success block, so data is comming, but its not executing deferred.resolve(data); properly...
in Web tool bar its giving me error,
ie. TypeError: undefined is not a function
My o/p is :
{"status":"SUCCESS","Message":"success","Token":"","Data":[{"Id":17,"UserId":"477f1919-6b80-4804-a325-ac0cb05bcd3e","UserName":"honey","FirstName":"honey","LastName":null,"ProfilePic":false,"Status":2}]}
How can I solve this error. ?
Ordinary $q promises don't have a .success() or .error() method, but you shouldn't be using the deferred antipattern anyway. Instead, do this:
JodoModule.factory('commonServices', function ($http, $rootScope) {
return {
getServiceData: function (url) {
$rootScope.loading = true;
var req = {
method: 'GET',
url: url
};
return $http(req).then(function (result) {
alert("data in service = " + JSON.stringify(result.data.Data));
return result.data;
});
}
};
});
Controller:
commonServices.getServiceData("My url").
then(function (data) {
alert(data);
}).
catch(function (result) {
alert("Got error");
});
Quite a bit cleaner, ay?
I´m trying to create an angular function inside on Service to return acess data via $http and then return to a desired scope.
So my service it something like this;
app.service('agrService', function ($http) {
this.testinho = function(){
return "teste";
}
this.bannerSlides = function(){
var dataUrl = "data/banner-rotator.json";
// Simple GET request example :
$http({
method: 'GET',
dataType: "json",
url: dataUrl
})
.success( function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
//console.log(data);
return data;
}).error( function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
alert("Niente, Nada, Caput");
});
}
})
Then i want to associate the returned data to a scope inside of my main App controller... like this:
app.controller('AppCtrl', function($scope, $http, agrService) {
$scope.slides = agrService.bannerSlides();
})
Then in my template i want to loop the data like this:
<div ng-repeat="slide in slides">
<div class="box" style="background: url('{{ slide.url }}') no-repeat center;"></div>
</div>
The problem is that the data it´s only available on success and i don´t know how to pass it to my scope slides!!!!!
What i´m doing wrong?
Many thanks in advance
bannerSlides() doesn't return the values you need right away. It returns a promise that you can use to obtain the value at a later time.
In your service you can use the .then() method of the promise that $http() produces to do initial handling of the result:
return $http({
method: 'GET',
dataType: "json",
url: dataUrl
}).then(function (data) {
// inspect/modify the received data and pass it onward
return data.data;
}, function (error) {
// inspect/modify the data and throw a new error or return data
throw error;
});
and then you can do this in your controller:
app.controller('AppCtrl', function($scope, $http, agrService) {
agrService.bannerSlides().then(function (data) {
$scope.slides = data;
});
})
Use this in your service
....
this.bannerSlides = function(){
var dataUrl = "data/banner-rotator.json";
return $http({
method: 'GET',
dataType: "json",
url: dataUrl
});
};
...
And this in your controller
agrService.bannerSlides().then(function(data) {
$scope.slides = data;
}, function() {
//error
});
you don't need $q promise inside the service because the $http is returning a promise by default
The $http service is a function which takes a single argument — a configuration object — that is
used to generate an HTTP request and returns a promise with two $http specific methods: success and error
reference
here is a Fiddle Demo
You need to return a promise and update your scope in the callback:
app.service('agrService', function ($q, $http) {
this.bannerSlides = function(){
var ret = $q.defer();
var dataUrl = "data/banner-rotator.json";
// Simple GET request example :
$http({
method: 'GET',
dataType: "json",
url: dataUrl
})
.success( function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
ret.resolve(data);
}).error( function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
ret.reject("Niente, Nada, Caput");
});
return ret.promise;
}
})
app.controller('AppCtrl', function($scope, $http, agrService) {
$scope.slides = null;
agrService.bannerSlides().then(function(data){
$scope.slides = data;
}, function(error){
// do something else
});
})
You can't return a regular variable from an async call because by the time this success block is excuted the function already finished it's iteration.
You need to return a promise object (as a guide line, and preffered do it from a service).
Following angular's doc for $q and $http you can build yourself a template for async calls handling.
The template should be something like that:
angular.module('mymodule').factory('MyAsyncService', function($q, http) {
var service = {
getData: function() {
var params ={};
var deferObject = $q.defer();
params.nameId = 1;
$http.get('/data', params).success(function(data) {
deferObject.resolve(data)
}).error(function(error) {
deferObject.reject(error)
});
return $q.promise;
}
}
});
angular.module('mymodule').controller('MyGettingNameCtrl', ['$scope', 'MyAsyncService', function ($scope, MyAsyncService) {
$scope.getData= function() {
MyAsyncService.getData().then(function(data) {
//do something with data
}, function(error) {
//Error
})
}
}]);
I have an http-method that gets some data from a google spreadsheet. I want to add this to the $scope so I can output it in the DOM. Later I might make a timed loop of this so that the $scope get's updated every 5 seconds or so.
I currently run the code in app.run:
angular.module('spreadsheet2angular', []).
run(function($http){
$http({method: 'GET', url: 'http://cors.io/spreadsheets.google.com/feeds/cells/0Aq_23rNPzvODdFlBOFRYWlQwUFBtcXlGamhQeU9Canc/od6/public/values?alt=json'}).
success(function(data, status, headers, config) {
var entries = data.feed.entry;
var phraces = [];
entries.forEach(function(entry){
var cell = entry.gs$cell;
if(!phraces[cell.row]){
phraces[cell.row] = {};
}
if(cell.col == 1)
{
phraces[cell.row].name = cell.$t;
}
else if(cell.col == 2)
{
phraces[cell.row].value = cell.$t;
}
});
phraces.forEach(function(phrace){
console.log(phrace);
});
}).
error(function(data, status, headers, config) {
console.log('error');
});
});
I'm new to angular, is this the best place to run it? I would like to run it as something that is easily reusable in different projects.
I think from what you've explained, a service would be perfect. Build it out then inject it in your controller. You can then call/use that service object whenever you would like.
I would use service/factory that returns promise. So we call async service method, get back promise and parse response into controller.
If you think to use the same call in the future, you can write generic method.
By the same way, if you are going to parse response by the same way in the future, the part of logic I would put into the service as well and wrap with $q . So the response still will be promise.
And this is an example I use that might help you to understand what I'm meaning:
app.service('apiService', ['$http', '$q', '$rootScope',
function($http, $q, $rootScope) {
var request = function(method, data) {
var deferred = $q.defer();
var configHttp = {
method: 'POST',
url: config.api + '/' + method
};
if (data !== undefined) {
configHttp.data = data;
}
$http(configHttp).success(function(data, status, headers) {
if (data.error === undefined) {
deferred.resolve(data);
} else {
deferred.reject(data);
}
}).error(function(data, status, headers) {
deferred.reject(data);
});
return deferred.promise;
}
return {
getItem: function() {
return request('get_item');
},
getItemByParams: function(id) {
return request('get_item_by_params', {id: id});
}
};
}
]);
I am new to AngularJS & working on a sample. In my sample app I have an MVC Web api (which returns some data from db) & it will be called from the Angular Services and returns the data to the Controller. The issue is I am getting the data in my Services success method properly but in my controller it always shows undefined & nothing is displayed in the view. Please see the code below:
My Controller code:
app.controller('CustomerController', function ($scope, customerService) {
//Perform the initialization
init();
function init() {
$scope.customers= customerService.getCustomers();
}
});
My Services code:
app.service('customerService', function ($http){
this.getCustomers = function () {
$http({
method: 'GET',
url: 'api/customer'
}).
success(function (data, status, headers, config) {
return data;
}).
error(function (data, status) {
console.log("Request Failed");
});
}
});
Please help me to fix this issue.
That's because your service defines the function getCustomers but the method itself doesn't actually return anything, it just makes an http call.
You need to provide a callback function in the form of something like
$http.get('/api/customer').success(successCallback);
and then have the callback return or set the data to your controller. To do it that way the callback would probably have to come from the controller itself, though.
or better yet, you could use a promise to handle the return when it comes back.
The promise could look something like
app.service('customerService', function ($http, $q){
this.getCustomers = function () {
var deferred = $q.defer();
$http({
method: 'GET',
url: 'api/customer'
}).
success(function (data, status, headers, config) {
deferred.resolve(data)
}).
error(function (data, status) {
deferred.reject(data);
});
return deferred;
}
});
Your problem is in your service implementation. You cannot simply return data since that is in the asynchronous success callback.
Instead you might return a promise and then handle that in your controller:
app.service('customerService', function ($http, $q){
this.getCustomers = function () {
var deferred = $q.defer();
$http({
method: 'GET',
url: 'api/customer'
})
.success(function (data, status, headers, config) {
// any required additional processing here
q.resolve(data);
})
.error(function (data, status) {
q.reject(data);
});
return deferred.promise;
}
});
Of course if you don't require the additional processing, you can also just return the result of the $http call (which is also a promise).
Then in your controller:
app.controller('CustomerController', function ($scope, customerService) {
//Perform the initialization
init();
function init() {
customerService.getCustomers()
.then(function(data) {
$scope.customers= data;
}, function(error) {
// error handling here
});
}
});
VERY late answer, but, Angular's $http methods return promises, so there's no need for wrapping everything into promise form with $q. So, you can just:
app.service('CustomerService', function ($http) {
this.getCustomers = function () {
return $http.get('/api/customer');
};
});
and then call the .success() or .error() shortcut methods in your client controller.
If you want to take it a step further and have a fully-fledged RESTful CustomerService without having to write this boilerplate, I'd recommend the restangular library, which makes all sorts of methods available to you - assuming of course your backend responds to HTTP verbs in the "standard fashion".
Then you could just do this:
app.service('CustomerService', function (Restangular) {
return Restangular.service('api/customer');
});
and call the methods Restangular makes available to you.
I use this for communication between Angular Web Data Service and Web Api Controller.
.factory('lookUpLedgerListByGLCode', function ($resource) {
return $resource(webApiBaseUrl + 'getILedgerListByGLCode', {}, {
query: { method: 'GET', isArray: true }
});
})
OR
.factory('bankList', function ($resource) {
return $resource(webApiBaseUrl + 'getBanklist_p', {}, {
post: {
method: 'POST', isArray: false,
headers: { 'Content-Type': 'application/json' }
}
});
})