AngularJS - Unable to call http serrvice using factory - javascript

To resolve my issue I have gone through many articles on different sites, but none resolved it.
I'm writing a simple AngularJS application. I'm quite new to Angular. I have written a factory method which call the $http service which gets the data from the web api. Web api is running fine and its returning the JSON object as expected.
Angular Code
var app = angular.module("app", [])
.controller("controller", function ($scope, WebFactory) {
$scope.data = "data";
$scope.error = "error";
$scope.data=WebFactory.getData();
})
.factory("WebFactory", function ($http) {
var obj = {};
obj.getData = function()
{
$http({
method: "GET",
url: "http://localhost:37103/api/employee",
}).then(function success(response) {
return response.data;
})
.then(function error(response) {
return response;
});
return 'No data';
}
return obj;
});
HTML code
<body ng-controller="controller">
data: {{data}}
<br/>
error: {{error}}
<br />
I have spent 2 days, but still dont know why its not working.

Try something like this instead:
var app = angular.module("app", [])
.controller("controller", function ($scope, WebFactory) {
$scope.data = "data";
$scope.error = "error";
$scope.data = {}
WebFactory.getData().then(function success(response) {
$scope.data = response.data;
});
})
.factory("WebFactory", function ($http) {
var obj = {};
obj.getData = function()
{
return $http({
method: "GET",
url: "http://localhost:37103/api/employee",
})
}
return obj;
});

First of all, you're missing an ng-app declaration
Secondly, you are misusing the then callback. It accepts three parameters: success callback, error callback, finally callback.
As the first then executes the success, then it executes the second callback that always returns the response, but I assume it is not intended to be that way and you could use the get function which is more easy to use.
It should be:
$http.get("http://localhost:37103/api/employee").then(function(response){
//Do something with successfull response
},
function(error){ //do something with the error});
See documentation about promises
Lastly, you are dealing with promises and async code, yet returning response or string instead of the promise with the result. So the getData() should look like this:
obj.getData = function(){
return $http.get("http://localhost:37103/api/employee");
}
And use the then(success,error,finally) callbacks in the controller or if you want to provide values on the error/finally callbacks in the service, you should use the $q service
obj.getData(){
var deferred = $q.defer();
$http.get(...).then(function(response){
deferred.resolve(response.data);
},
function(error){
deferred.reject("No Data");
});
return deferred.promise;
}
Of course you would have to provide $q service to the WebFactory

Related

is it possible not to execute the promise (.then ()) in the controller when there is an error in a web request?

I'm currently using a factory called http that when I invoke it, I make a web request. this receives as a parameter the url of the web request.
app.factory('http', function ($http) {
var oHttp = {}
oHttp.getData= function (url) {
var config={
method: 'GET',
url: url
}
return $http(config).then(function(data) {
oHttp.data=data.data;
},function(response) {
alert("problem, can you trying later please?")
});
}
return oHttp;
});
function HelloCtrl($scope, http) {
http.getData('https://www.reddit.com/.json1').then(function(){
if(http.data!=undefined){
console.log(http.data)
}
})
}
I would like the promise not to be executed on the controller if the result of the web request is not satisfied or there is a problem. is there any better solution? I want to avoid doing this every time I make a web request, or do not know if it is the best way (see the if):
//I am putting "1" to the end of the url to generate an error.
http.getData('https://www.reddit.com/.json1').then(function(){
//validate that the result of the request != undefined
if(http.data!=undefined){
alert(http.data.kind)
}
})
In my real project I make n web requests using my factory http, I do not want to do this validation always. I do not know if I always have to do it or there is another solution.
this is my code:
https://plnkr.co/edit/8ZqsgcUIzLAaI9Vd2awR?p=preview
In rejection handlers it is important to re-throw the error response. Otherwise the rejected promise is converted to a successful promise:
app.factory('http', function ($http) {
var oHttp= {};
oHttp.getData= function (url) {
var config={
method: 'GET',
url: url
}
return $http(config).then(function(response) {
̶o̶H̶t̶t̶p̶.̶d̶a̶t̶a̶=̶r̶e̶s̶p̶o̶n̶s̶e̶.̶d̶a̶t̶a̶;̶
return response.data;
},function(response) {
alert("problem, can you trying later please?")
//IMPORTANT re-throw error
throw response;
});
}
return oHttp;
});
In the controller:
http.getData('https://www.reddit.com/.json1')
.then(function(data){
console(data)
}).catch(response) {
console.log("ERROR: ", response.status);
});
For more information, see You're Missing the Point of Promises.
In Service
app.factory('http', function ($http) {
var oHttp = {}
oHttp.getData= function () {
return $http({
method: 'GET',
url: 'https://www.reddit.com/.json1'
});
}
return oHttp;
});
In controller
function HelloCtrl($scope, http) {
var httpPromise = http.getData();
httpPromise.then(function(response){
console.log(response);
});
httpPromise.error(function(){
})
}
So I tried this in codepen having ripped your code out of plinkr
https://codepen.io/PocketNinjaDesign/pen/oGOeYe
The code wouldn't work at all...But I changed the function HelloCtrl to a controller and it seemed happier....?
I also set response.data to default to an empty object as well. So that way if you're populating the data in the page it will be empty if nothing arrived. You can then in some instances on the site check the length if it's really required.
app.factory('http', function ($http) {
var oHttp = {}
oHttp.data = {};
oHttp.getData= function (url) {
var config = {
method: 'GET',
url: url
}
return $http(config).then(function(response) {
oHttp.data = response.data || {};
}, function(response) {
alert("problem, can you trying later please?")
});
}
return oHttp;
});
app.controller('HelloCtrl', function($scope, http) {
http.getData('https://www.reddit.com/.json').then(function(){
alert(http.data.kind);
})
});

Angularjs custom service variable undefined by $http success

I wrote an angular service that is supposed to load customer details over http and store them for future use (in a singleton pattern).
However, when the http call returns successfuly, the variable into which I want to inject the data is undefined and an error is thrown.
Here's the code:
NBApp.service("serverDataService", ['$http', '$q', function ($http, $q) {
var currentMemberDetails = [];
this.currentMember = function (){
if (this.currentMemberDetails.length>0)
return this.currentMemberDetails[0];
return null;
};
this.getMemberDetails = function (cardId) {
//TBD - call members details web service
var deferred = $q.defer();
$http({
method: 'GET',
url: 'resources/customer.json'
}).then
(
function success(response) {
this.currentMemberDetails.push(response.data);
deferred.resolve(data);
},
function failure(response) {
deferred.reject(response);
}
);
return deferred.promise;
};
}]);
The currentMemberDetails is undefined, as shown by the chrome dev console.
Instead of
this.currentMemberDetails.push(response.data);
Use
currentMemberDetails.push(response.data);

Angular $http get works in browser but not on device - Ionic

I have a factory returning an object calling an internal resource containing JSON as so:
.factory('cardFactory', function ($q, $http) {
return {
getOtherStuff: function () {
var deferred = $q.defer(),
httpPromise = $http.get('/static/cards.json');
httpPromise.then(function (response) {
deferred.resolve(response);
}, function (error) {
console.error(error);
});
return deferred.promise;
}
};
});
In my controller I call it like this:
var cardSuccess = function(data, status, headers, config) {
$scope.cards = data.data;
};
cardFactory.getOtherStuff()
.then(cardSuccess, cardError);
In the browser $scope.cards in populated but on the device it doesn't populate.
Any ideas why?
Hmm.., not sure.
I have it in a different way in my Ionic app, working great.
.factory('cardFactory', function ( $http ) {
var promise;
var cards = {
getOtherStuff: function() {
if ( !promise ) {
// $http returns a promise, which has a then function, which also returns a promise
promise = $http.get( '/static/cards.json' ).then(function (response) {
// The then function here is an opportunity to modify the response
// The return value gets picked up by the then in the controller.
return response.data;
});
}
return promise; // Return the promise to the controller
}
};
return cards;
})
Then, on the controller, calling it by:
$scope.getData = function() {
// Call the async method and then do stuff with what is returned inside our own then function
cardFactory.getOtherStuff().then(function(d) {
$scope.cards= d;
});
}
$scope.getData();
Hope it helps.
[EDIT:] Could it be the $http.get url, being relative? Have you tried with an absolute url?
Replace $scope.cards=data.data with "$scope.cards=data"
var cardSuccess = function(data, status, headers, config) {
$scope.cards = data;
};
try removing the leading slash in your url for $http. Try using 'static/cards.json' instead of '/static/cards.json'
I actually had the same problem and this fixed it for me. Hope it helps!

asynchronous call in angular js

Hi all I am new to angular js,here I want to fetch the json from server to the controller so that I can handle the data,but whats happening here is the first alert -11 is called then alert 2 is called and in the end alert 1 is being called ,I read about promise so I tried it but still not working,I want it to happen one after another please help me .Thanks in advance
sampleApp.controller('firstpage', function ($scope, $q, $http, $templateCache, onlinedata, offlinedata) {
$scope.message = 'This is Add new order screen';
var defer = $q.defer();
defer.promise.then(function () {
$scope.method = 'POST';
$scope.url = 'http://ncrts.com/ncrtssales_compadmin/webservices/user_login';
$scope.fetch = function () {
$scope.code = null;
$scope.response = null;
alert($scope.response + 11) //alert11
$http({
method: $scope.method,
url: $scope.url,
cache: $templateCache
}).
success(function (data, status) {
$scope.status = status;
$scope.message = data;
alert($scope.message + 1) //alert1
}).
error(function (data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
});
};
$scope.fetch();
})
.then(function () {
alert($scope.message + 2); //alert 2
})
defer.resolve();
//alert($scope.remember)
});
You have to use the resolve and reject functions to handle the response with the promise. You can find more information about promise in the AngularJS documentation. I made a little change in your code to show you how you can achieve what you want.
sampleApp.controller('firstpage', function ($scope, $q, $http, $templateCache, onlinedata, offlinedata) {
$scope.message = 'This is Add new order screen';
var defer = $q.defer();
$scope.method = 'POST';
$scope.url = 'http://ncrts.com/ncrtssales_compadmin/webservices/user_login';
$scope.fetch = function () {
$scope.code = null;
$scope.response = null;
alert($scope.response + 11) //alert11
var defer = $q.defer();
$http({
method: $scope.method,
url: $scope.url,
cache: $templateCache
}).
success(function (data, status) {
//$scope.status = status;
$scope.message = data;
alert($scope.message + 1) //alert1
defer.resolve({
status: status,
message: data
});
}).
error(function (data, status) {
var data = data || "Request failed";
//$scope.status = status;
defer.reject({
status: status,
message: data
});
});
return defer.promise;
};
$scope.fetch().then(function (data) {
alert('Status: ' + data.status);
alert('Message: ' + data.message);
});
});
I am very confused by the formatting of your code. It may help you to write the asynchronous call in a service and then inject the service into your controller. Keeping that in mind, here is some general advice that I've learned regarding asynchronous calls and promises in AngularJS:
Your service should initially return a deferred promise. This promise
should then be resolved on success() of the asynchronous call.
After $http() returns, but before success() returns, you have an
unresolved promise. If you have code that you want to run after the
promise is resolved, you need to use then() to indicate that you
want to execute the code within the then() block once you've
received data (and resolved the promise).
Not using then() for this
situation will cause errors because you will be attempting to access
data that doesn't yet exist.
It seems from your code that you are aware of the necessary coding strategy for what you need, but it will always help to isolate asynchronous calls into services so that the framework can make your life easier. Good luck.

unable to get data from $q into scope

I'm trying to bind some data being returned from an API to my scope using promises with $q, I am able to pull the data from the server without any issue (I can see JSON being returned using fiddler) however the $scope variable remains empty, any help would be greatly appreciated! Thanks in advance.
Code:
toDoListService.js
app.factory("toDoListService", function ($http, $q) {
var deferred = $q.defer();
return {
get: function () {
$http({ method: 'GET', url: '/api/todo/' }).
success(function (data) {
deferred.resolve(data);
}).
error(function (data, status, headers, config) {
deferred.reject(status);
});
return deferred.promise;
}
});
toDoListController.js
app.controller("toDoListController", function($scope, toDoListService){
$scope.toDoList = toDoListService.get();
});
First of all you should put var deferred = $q.defer(); in your get function, so that every get has it's own deferred object.
Second what get actually returns is a promise. So you need to access you data in this way:
app.controller("toDoListController", function($scope, toDoListService){
toDoListService.get().then(function(data){
$scope.toDoList = data;
});
});
Right now, your $scope.toDoList is bound to a promise. This means of binding used to work, but was deprecated in, I think, 1.2.
As Michael suggests, you must do:
app.controller("toDoListController", function($scope, toDoListService){
toDoListService.get().then(function(data){
$scope.toDoList = data;
});
});
Also, using $q is not required here at all, as $http returns a promise anyway. Therefore, you could just do:
app.factory("toDoListService", function ($http){
return {
get: function () {
return $http({ method: 'GET', url: '/api/todo/' });
}
};
});
You can simplify your code by using this:
toDoListService.js
app.factory("toDoListService", function ($http, $q) {
return {
get: function () {
return $http({ method: 'GET', url: '/api/todo/' });
}
}
});
toDoListController.js
app.controller("toDoListController", function($scope, toDoListService) {
toDoListService.get().then(function(response){
$scope.toDoList = response.data;
return response;
});
});
Be sure to return response in your success callback, otherwise chained promises would not receive it.

Categories

Resources