I have an angular factory doing some $http communication to the server and returning a string. However I get the Cannot read property 'then' of undefined error. I read here and here with similar problems however I was not able to resolve my problem.
This is the service code:
factory("availabilityService", ['$http', function ($http) {
return {
checkAvailability1: function (element, string) {
// ..... some object creation code ......
$http({
method: 'POST',
url: 'server/server.php',
data: AvailableObj,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(function successCallback(response) {
return response;
}, function errorCallback(response) {
});
}
}
}]);
Inside a controller:
$scope.checkAvailability = function (element, string) {
availabilityService.checkAvailability1(element, string).then(function (response) { //on this line the error occurs
console.log(response);
});
You need to return the promise returned by $http i.e add a 'return' in front of $http to get your code working like below :
return $http(...)
.then(function successCallback(response) {
return response;
}, function errorCallback(response) {
});
This is because, the function you have called from the controller should have a .then method on it i.e it should be a promise. checkAvailability1 in angular returns a promise which needs to be returned back by your function $http in the factory. You are just returning the response from the success callback which is not expected by your method in the controller.
Related
This is my service:
app.factory("ResourceService", function ($resource, $q, $http) {
return {
getAll: function () {
var deferred = $q.defer();
$http.get('https://dog.ceo/api/breeds/list/all').then(function (response) {
deferred.resolve(response);
}, function (error) {
deferred.reject(error);
});
return deferred.promise;
},
allUsingResource: function () {
return $resource('https://dog.ceo/api/breeds/list/all');
}
}
});
This is my controller:
app.controller("Controller", function ($scope, ResourceService) {
function getAll() {
ResourceService.getAll().then(function (response) {
$scope.all = response.data;
}, function (error) {
console.log(error);
});
}
function runAll() {
var data = ResourceService.allUsingResource();
data.query(function (response) {
console.log(response);
}, function (error) {
console.log(error);
});
}
runAll();
getAll();
});
While everything goes swell with $http, i get badcfg with $resource:
Error: [$resource:badcfg] http://errors.angularjs.org/1.6.5/$resource/badcfg?p0=query&p1=array&p2=object&p3=GET&p4=https%3A%2F%2Fdog.ceo%2Fapi%2Fbreeds%2Flist%2Fall
What am I missing?
When you run data.query on $resource object by default it expects array in response:
'query': {method:'GET', isArray:true},
So be sure you return an array and not an object from https://dog.ceo/api/breeds/list/all
Read error from URL Angularjs Provided for you:
https://docs.angularjs.org/error/$resource/badcfg?p0=query&p1=array&p2=object&p3=GET&p4=https:%2F%2Fdog.ceo%2Fapi%2Fbreeds%2Flist%2Fall
Error in resource configuration for action query. Expected response to contain an array but got an object (Request: GET https://dog.ceo/api/breeds/list/all)
Description
This error occurs when the $resource service expects a response that can be deserialized as an array but receives an object, or vice versa. By default, all resource actions expect objects, except query which expects arrays.
To resolve this error, make sure your $resource configuration matches the actual format of the data returned from the server.
For more information, see the $resource API reference documentation.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I am trying to resolve a $http get request before I return it but I seem to always get undefined result.
I have spent a lot of time researching and trying different methods out and still cannot seem to solve it, can any of you see where I am going wrong?
This is the services.js file
(function() {
angular.module('Home')
.factory('HomeService', HomeService);
function HomeService($http) {
return {
getStatus: getStatus()
};
function getStatus($scope) {
$http({
method: 'GET',
url: 'http://rubynode-iot.chimera.projects.local/sparkDrivers'
}).then(function successCallback(response) {
}, function errorCallback(response) {
});
}
}
}());
This is the controller where I hope to send the resolved result.
function HomeController(HomeService) {
HomeService.getStatus;
console.log(HomeService.getStatus)
};
This is learning to use promises. Here is a quick way to get what you want. I would look into promises and the $q function which you can also implement but I won't detail here. Angular docs on $q
Basically, you return the promise from the service and implement the code to run when the promise returns inside the controller.
(function() {
angular.module('Home')
.factory('HomeService', HomeService);
function HomeService($http) {
return {
getStatus: getStatus
};
function getStatus($scope) {
return $http({
method: 'GET',
url: 'http://rubynode-iot.chimera.projects.local/sparkDrivers'
});
}
}
// Your controller should use the service like this
function HomeController(HomeService) {
HomeService.getStatus().then(function(response){
console.log(response.data);
},function(response){
console.log('an error occured');
});
}());
You can return your promise in your service so it can be resolved in your controller:
Service:
function getStatus() {
var promise = $http({
method: 'GET',
url: 'http://rubynode-iot.chimera.projects.local/sparkDrivers'
});
promise.then(function(data) {
return data.data;
});
};
Controller:
HomeService.getStatus().then(function(status) {
$scope.status = status;
});
try this:
(function() {
angular.module('Home').service('HomeService', HomeService);
function HomeService($http) {
this.getStatus = function() {
return $http({
method: 'GET',
url: 'http://rubynode-iot.chimera.projects.local/sparkDrivers'
}).then(function successCallback(response) {
}, function errorCallback(response) {
});
}
}
}());
and in your controller:
angular.module('yourApp')
.controller('yourController', ['HomeService',
function(HomeService){
function getStatusFromSrv(){
var status;
HomeService.getStatus().then(function(response){
status = response;
console.log("status:" , status);
});
}
}
])
I'm a bit confused by mixing promises and callbacks
I'm trying to do something like this in a factory
startRecord: function (data) {
return $q(function(resolve, reject) {
myFunction(data,resolve,reject);
})
}
which calls
function myFunction(data,callback,error){
...do stuff
if(worked)
callback(response)
else
error(err)
}
And then call it from within my controller like
factory.startRecord(data).then(function(data)...).catch(function(error)...);
However the then or catch are never called..
Am I going the right way about this?
My problem was the callback was being fired with an empty message before the full message was sent. I had to add some extra checks to stop the callback being fired until the message was ready.
Angular $http call it self return promise, you just need to call it perfectly.
Sample code :
Factory:
angular.module(ApplicationName).factory('calendarFactory', ['$http', function ($http) {
calendarFactory.testCall = function (request_params) {
var req = {
method: 'POST/GET',
url: <URL>,
headers: {
'Content-Type': 'application/json'
},
data: request_params
};
return $http(req);
}
}
Controller :
function testCall(start, end) {
var request_paramas = {
start: start.toString(),
end: end.toString()
};
calendarFactory.testCall(request_paramas).then(
function(success){
//Success method
},function(error){
//Error method
})
}
Here I made a back-end http call from factory itself
I want create 1 service where i can POST the data and on success i can again GET the data and update the $scope.variable??
How to do that?
I've tried this way:
angular.module('mvc')
.factory('ajaxService', function($http) {
return {
getAjaxData: function(response) {
$http.get(url).success(response);
return response;
},
postAjaxdata: function(postData){
$http({
method: "post",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
url: url,
data: data
})
.success(function(response){
ajaxService.getAjaxData(function(response) {
$scope.foo = response;
});
});
}
}
});
Capture this in postAjaxdata() to be used in the success callback to call getAjaxData().
You don't have access to the scope inside of the service (nor do you want to access it from a service). The Angular convention is to return a promise to the controller so that it can apply the response value to the scope when the promise is resolved. You can also do this using callbacks (to be consistent with the code that was posted). Here, I've added a callback to postAjaxdata()...
angular.module('mvc')
.factory('ajaxService', function($http) {
return {
getAjaxData: function(successCallback) {
$http.get(url).success(successCallback);
return successCallback;
},
postAjaxdata: function(postData, successCallback){
var that = this;
$http({
method: "post",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
url: url,
data: data
})
.success(function(){
that.getAjaxData(successCallback);
});
}
}
});
The controller should look something like this...
function controller ($scope, ajaxService) {
// ...
ajaxService.postAjaxdata(postData, function (response) {
$scope.foo = response;
});
}
The main issue is that you can't set scope variables in the way you attempted to from the service.
You could instead use the $q service to return a promise which, when resolved, is set to your $scope.foo variable:
.factory('ajaxService', function($http, $q) {
var ajaxService = {
getAjaxData: function() {
return $http.get(url);
},
postAjaxdata: function(postData){
var deferred = $q.defer();
$http({
method: "post",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
url: url,
data: postData
})
.success(function(){
deferred.resolve(ajaxService.getAjaxData());
});
return deferred.promise;
}
};
return ajaxService;
});
You'll also notice that I set the body of your factory to a named variable, which you can then use to call functions internally (as you did with ajaxService.getAjaxData()) before returning.
Then, in your controller, you could set your scope variable like this:
.controller('MyController', function($scope, ajaxService){
ajaxService.postAjaxdata().then(function(results){
$scope.foo = results.data;
})
})
Working Plunker
Note: my answer is not entirely dissimilar to Anthony Chu's. I noticed that he posted his just before mine, but I went ahead anyway since mine takes a slightly different approach, utilizing promises instead of callbacks.
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' }
}
});
})