Angular JS $http request - caching success response - javascript

I've got a simple dataFactory that retrieves some posts:
dataFactory.getPosts = function () {
if (this.httpPostsData == null) {
this.httpPostsData = $http.get("http://localhost/matImms/wp-json/posts?type=journey&filter[posts_per_page]=-1&filter[order]=ASC&filer[orderby]=date")
.success(function (posts) {
})
.error(function (posts) {
console.log('Unable to load post data: ' + JSON.stringify(posts));
});
}
return (this.httpPostsData);
}
The controller calls the factory and I understand that the posts are promises -so there is some stuff done on success and some stuff that is done anyway. This works fine.
.controller('CardsCtrl', function($scope, dataFactory,
$ionicSlideBoxDelegate, $stateParams) {
var parentID = $stateParams.parentID;
var keyIDNumber = $stateParams.keyID;
$scope.card = [];
var httpcall = dataFactory.getPosts()
.success(function (posts) {
$scope.card = dataFactory.getChildPosts(parentID, posts, keyIDNumber);
$ionicSlideBoxDelegate.update();
});
// do other stuff ......
});
However, I'm now trying to cache the post data - but when the controller is called a second time it returns the error .success is not a function. I assume the is because the posts have already been returned - but how do I handle this?

That's because you're not returning the $http.get, you're returning the promise after .success and .error have already been handled.
You can either change the controller to call .then on the return, or change the service to just return the $http.get (remove the .success and .error) and handle them in the controller.
If you change the controller to use .then you'll also need to update the .success function in the service to return posts;.

Have you tried setting the cache option to true in your $http call? Like here https://stackoverflow.com/a/14117744/1283740
Maybe something like this...
angular.module('foo', [])
.factory('dataFactory', ['$http', function($http){
var dataFactory = {
getPosts: getPosts
};
function getPosts(){
var url = "http://localhost/matImms/wp-json/posts?type=journey&filter[posts_per_page]=-1&filter[order]=ASC&filer[orderby]=date"
return $http({ cache: true, url: url, method: 'GET'})
.error(function (posts) {
console.log('Unable to load post data: ' + JSON.stringify(posts));
});
};
return dataFactory;
}])

Related

$http.post is not a function

I am trying to submit a form data to an API endpoint which I created. I have tested it in PostMan and the API functions well and I can get the data in successfully. But while connecting that API endpoint to a function in angular js I get the following error.
Heres my code:
$scope.saveSession = function() {
$http.post("/session/survey", $scope.session).success(function(data, status) {
$window.location.href = '/';
console.log("Sucessfully getting data" + JSON.stringify(data));
})
}
Note:
$scope.session is an object that being populated by using the ng-model tag.
For example:
<input type="text" ng-model="session.title">
Edit (Controller Code):
// This is our controller for the bio page
var session = angular.module('session', ['sessionService'])
session.controller('sessionCtrl', function($scope, $http, $window, sessionServices) {
$scope.session = {};
$scope.saveSession = function() {
$scope.session.sessionNo = 1;
$scope.session.coach = "mmmm";
$scope.session.modules = "wokr place";
//console.log(user);
$http.post("/session/survey", $scope.session).success(function(data, status) {
$window.location.href = '/';
console.log("Sucessfully getting added bio" + JSON.stringify(data));
})
};
});
That's because .success() really isn't a function. As the documentation explains, a promise is returned by $http.post() which you can chain with .then()
$http.post('/someUrl', data, config).then(successCallback, errorCallback);
Use promises, "success" function doesn't exists in $http object($http success and error methods are available only in older versions of Angular 1.x, but they've removed in Angular 1.6):
// Simple GET request example:
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
More in official documentation https://docs.angularjs.org/api/ng/service/$http
It's because you're using $http.post().success.
Try;
$scope.saveSession = function() {
$http.post("/session/survey", $scope.session).then(function(data, status) {
$window.location.href = '/';
console.log("Sucessfully getting data" + JSON.stringify(data));
})
}
We use .then to return a "promise" from the $http service.
Hope it helps!
I just dealt with a similar issue with versions 1.7.2 and 1.7.4. It's not exactly the same issue because I was never using .success but I'm posting here because this post comes up first when searching.
When using the shortcut version $http.post(/api/endpoint/', data) I would get:
"TypeError: $http.post is not a function"
And if I used it with the callbacks exactly as it appears in the documentation:
$http({method: 'POST', url: '/api/endpoint/', data: $scope.newObject}).then(function (response) {
$scope.status = response.status;
$scope.data = response.data;
}, function (response) {
$scope.data = response.data || 'Request failed';
$scope.status = response.status;
});
I was getting
"TypeError: $http(...).then is not a function"
In this case the problem was that I had both $resource and $http in the same controller. Not sure if this is the intended behavior but removing $resource suddenly made $http work again.
Hopefully this helps someone else

AngularJS - Best approach for taking data from factory and if not there use http service

In my angularJS application, I have set data received from one controller's ajax and put in factory method to reuse in other controllers. The problem is when user reload page, this factory method is useless.
app.factory('factory', function () {
return {
set: set,
get: get
}
});
app.controller ('testController', function ($scope, factory) {
if (factory.get('name')) {
$scope.name= factory.get('name');
} else {
$http.get(url).then(function(res) {
$scope.name= res.name;
factory.set('name', res.name);
});
}
});
What is the best way to retrieve this check in factory method which will get value from factory, if not there take from http service and in controller common code needs handle these two cases that done factory method?
Here when data taken from http service it returns promise otherwise plain value.
This code will fetch data from server if the 'cachedResult' variable is not set, otherwise return a promise from the stored variable.
app.factory('factoryName', ['$http','$q', function($http,$q) {
var cahedResult = null;
var myMethod = function(args) {
var deferred = $q.defer();
if (cahedResult){
deferred.resolve({ data : cahedResult });
return deferred.promise;
}
$http.get(....).then(function(response){
cahedResult = response.data;
deferred.resolve({ data : cahedResult });
},function(error){
deferred.reject('error');
});
}
};
return {
myMethod : myMethod
}
])
But you could also store the data in local storage or in a cookie when the first controller fetch the info so that it's available even if user refresh the browser.
First create a factory :
app.factory('factoryName', ['$http','$q', function($http,$q) {
return {
getData : function(arg1,arg2) {
return $http.get('/api-url'+arg1+'/'+arg2)
.then(function(response) {
if (typeof response.data === 'object') {
return response.data;
} else {
return $q.reject(response.data);
}
}, function(response) {
return $q.reject(response.data);
});
}
}
}])
Provide every api details in this factory, so you can use this factory in multiple controllers.
In Controller inject the factory (factoryName) as a dependency.
app.controller ('testController',['$scope', 'factoryName', function($scope, factoryName) {
factoryName.getData(arg1,arg2,...)
.then(function(data) {
console.log(data);
}, function(error){
console.log(error);
});
}]);
For detailed description :- http://sauceio.com/index.php/2014/07/angularjs-data-models-http-vs-resource-vs-restangular/
Directly return a promise from your factory
app.factory('factoryName', function () {
var connectionurl ='...'; //Sample: http://localhost:59526/Services.svc
return {
connectionurl : connectionurl ,
methodName: function (parameters) {
$http({
method: 'GET',
url: connectionurl + 'servicemethod_name'
})}
}
}
});
In this case your controller will look like
app.controller ('testController', function ($scope, factoryName) {
factoryName.methodName(parameters).then(function(){
$scope.variable=response.data;
/*binding your result to scope object*/
}, function() {
/*what happens when error occurs**/
});
});
Other way is directly bind to a scope object through success callback function
app.factory('factoryName', function () {
var connectionurl ='...'; //Sample: http://localhost:59526/Services.svc
return {
connectionurl : connectionurl ,
methodName: function (parameters,successcallback) {
$http({
method: 'GET',
url: connectionurl + 'servicemethod_name'
}).success(function (data, status, headers, config) {
successcallback(data);
})
.error(function (data, status, headers, config) {
$log.warn(data, status, headers, config);
});
}
}
});
In this case your controller will look like
app.controller ('testController', function ($scope, factoryName) {
factoryName.methodName(parameters,function(response){
/* your success actions*/
$scope.variable=response;
});
});
In the second case your error is handled in the factory itself. How ever you can also use errorcallback function.

AngularJS http call (complete syntax)

I'm new to AngularJS and
I needed to know if we can make a jQuery like Ajax call in Angular and wanted to know it's complete syntax,
if anyone could help me making the whole code syntax.
Example in jQuery I could do something like -
$.ajax(
{
url: 'someURL',
type: 'POST',
async: false,
data:
{
something: something,
somethingelse: somethingelse
},
beforeSend: function()
{
$('#someID').addClass('spinner');
},
success: function(response)
{
$('#someID').removeClass('spinner');
console.log(response);
},
complete: function(response)
{
$('#someID').removeClass('spinner');
console.log(response);
},
error: function (errorResp)
{
console.log(errorResp);
}
});
Now here's what I found out on making http call in Angular,
Need help in building the complete syntax, with all possible options -
var req = {
method: 'POST',
url: 'someURL',
headers: {
'Content-Type': undefined
},
data: {
//goes in the Payload, if I'm not wrong
something: 'something'
},
params:{
//goes as Query Params
something: 'something',
somethingElse: 'somethingElse'
}
}
$http(req)
.then(function()
{
//success function
},
function()
{
//Error function
});
now what if I want to attach a spinner on some id in the BeforeSend function like in jQuery and remove the spinner in success,
What is the Angular's way as a like to like for BeforeSend or making the http call async?
Angular even let you control this better :). Two ways can be chosen here:
1. Wrapping $http
You can write for each request with by using a wrapper of $http which will add some methods before and after you made request
app.factory('httpService',function($http){
function beginRequest() {};
function afterRequest() {};
return {
makeRequest: function(requestConfig){
beginRequest();
return $http(requestConfig).then(function(result){
afterRequest(result);
});
}
}
})
Then each time you can call this function to make a request. This is not new.
2. Using interceptor
Angular has a better way to handle for all request. It use a new concept named 'interceptor'. You write your interceptor as a normal service and push one or many interceptors into $http service and depend on type of interceptor, it will be called each time your request happen. Look at this picture to think about interceptor:
Some common task for interceptor can be: Add/remove a loading icon, add some more decorator to your http config such as token key, validate request, validate responded data, recover some request...
Here is example of a interceptor that add a token key into headers of a request
app.service('APIInterceptor', function($rootScope, UserService) {
var service = this;
service.request = function(config) {
var currentUser = UserService.getCurrentUser(),
access_token = currentUser ? currentUser.access_token : null;
if (access_token) {
config.headers.authorization = access_token;
}
return config;
};
service.responseError = function(response) {
return response;
};
})
Then add interceptor to your $http:
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('APIInterceptor');
}]);
Now all request will be added a token key to header. cool right?
See here for more information:
there is eveyrthing here to help with your question :https://docs.angularjs.org/api/ng/service/$q http://chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/
$http functions are async by default.
And regarding the beforesend function, you could wrap the http call in a function and add the spinner just before making the call and remove it in the success call back. Something like this,
var makeHttpRequest = function(){
$('#someID').addClass('spinner');
$http(req).then(function(){
$('#someID').removeClass('spinner');
//rest processing for success callback
},function(){
$('#someID').removeClass('spinner');
//Error callback
});
}
The way I have implemented complex get and post in my angular application is as below:
Create a CRUDService as below:
yourApp.service('CRUDService', function ($q, $http) {
this.post = function (value, uri) {
var request = $http({
method: "post",
url: uri,
data: value
});
return request;
}
this.get = function (uri) {
var request = $http({
method: "get",
url: uri
});
return request;
}
});
As you can see this service simply returns a get/post object. Somewhere in my controller I use this service as below:
$('#exampleButton').button("loading"); //set the element in loading/spinning state here
var getObj = CRUDService.get("/api/get/something");
getObj.then(function(data){
//do something
$('#exampleButton').button("reset"); //reset element here
}, function(err){
//handle error
$('#exampleButton').button("loading"); //reset element here
});
$('#exampleButton').button("loading"); //set the element in loading/spinning state here
var postObj = CRUDService.post(postData,"/api/get/something");
postObj.then(function(data){
//do something
$('#exampleButton').button("reset"); //reset element here
}, function(err){
//handle error
$('#exampleButton').button("loading"); //reset element here
});
I hope this helps :)
The http call is async - it returns a promise that you can then handle with the try() and catch() methods. You can simply wrap your calls i.e.
function makeRequest() {
$scope.showSpinner = true;
$http
.get('http://www.example.com')
.then(function (response) {
$scope.showSpinner = false;
})
.catch(function (err) {
$scope.showSpinner = false;
});
}
If you would however like you use familiar syntax akin to jQuery then you can push your own custom interceptors. This will allow you intercept the requests and response and do whatever you want. In the below example we call functions if they are defined.
angular
.module('app', [])
.config(appConfig)
.factory('HttpInterceptors', httpInterceptors)
.controller('MyController', myController);
// app config
appConfig.$inject = ['$httpProvider'];
function appConfig($httpProvider) {
// add out interceptors to the http provider
$httpProvider.interceptors.push('HttpInterceptors');
}
// http interceptor definition
function httpInterceptors() {
return {
request: function(request) {
if (angular.isFunction(request.beforeSend)) {
request.beforeSend();
}
return request;
},
response: function(response) {
if (angular.isFunction(response.config.onComplete)) {
response.config.onComplete();
}
return response;
}
}
}
// controlller
myController.$inject = ['$scope', '$http', '$timeout'];
function myController($scope, $http, $timeout) {
$scope.showSpinner = false;
$http({
method: 'GET',
url: 'https://raw.githubusercontent.com/dart-lang/test/master/LICENSE',
beforeSend: function() {
$scope.showSpinner = true;
},
onComplete: function() {
$timeout(function() {
console.log('done');
$scope.showSpinner = false;
}, 1000);
}})
.then(function(response) {
console.log('success');
})
.catch(function(err) {
console.error('fail');
});
}
.spinner {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<div ng-app='app' ng-controller='MyController'>
<div ng-class='{spinner: showSpinner}'>
Hello World!
</div>
</div>

Apply scope to promise .then() functions from service

I'm new to AngularJS.
I'm calling a service from a controller that is communicating with a webservice. the service returns a promise to the controller. Now I want to apply the data that is available on the success function of the promise to $scope. How can I achieve this? I already tried to do $scope.$apply() on the service call or the promise success function, but this just gives me errors.
Controller:
angular.module('home')
.controller('HomeCtrl',
['$scope', 'myService',
function ($scope, myService) {
$scope.data = [];
$scope.getData = function () {
// this is triggered via btn click
myService.getSomeData(reqData)
.then(
function success(res){
// apply res.data to $scope.data ?
},
function failure(err){
//error handling
}
);
}
}]);
Service:
angular.module('myService')
.factory('myService', ['$http', '$rootScope',
function ($http, $rootScope) {
return {
generalWebServiceProxy: function (webserviceName, data, xml) {
// do some xml stuff, settings header etc
return $http({
method: 'POST',
url: URL,
headers: headers,
data: data
});
},
getSomeData: function (data) {
return this.generalWebServiceProxy('WSName', data, true).then(/* do something here and return data*/);
}
}
}]);
Thanks in advance!
$http returns a promise where the server response is resolved. That response object contains things like status, data, header, etc.. etc...
Your service should handle these responses itself. So that the method setSomeData resolves to that data. Right now, it's resolving to the server response which isn't very useful for your directive.
generalWebServiceProxy: function (webserviceName, data, xml) {
// this method is return a promise
return $http({...});
},
// this method uses "promise chaining"
getSomeData: function (data) {
return this.generalWebServiceProxy(
'WSName',
data,
true).then(function(response) {
if(response.status == 200) {
return response.data;
}
throw new Error("Unexpected response:"+response.status);
});
}
In the above code I've done something called promise chaining. That's where the return value of a then mutates the resolve value. So the next promise then call will have response.data as the parameter.
Later in your directive you can use the promise returned by the service as a regular promise. It just resolves to the data in the response.
$scope.getData = function () {
myService.getSomeData(reqData)
.then(function success(data) {
// ^^ data is actually the value `response.data` from the service
});
}
What about error handling?
There are two kinds of errors with $http. There are HTTP errors like unable to resolve host, failure to connect or timeouts, and then there are response errors. Such as content missing or content not found. Some of these can be handled with the promise failure callback, and some are successful responses that you don't want.
So in my example I restrict success to mean an HTTP 200 response. You might want to check that the data given back is what you were expecting (for example, is it an array?).
I've found it better to handle errors using a HTTP interceptor. Otherwise you have to implement error handles in every directive that uses the service.
$http is a promise and over here you not returning the promise and using it as a promise in the controller.
Modified Service:
angular.module('myService')
.factory('myService', ['$http', '$rootScope',
function ($http, $rootScope) {
return {
generalWebServiceProxy: function (webserviceName, data, xml) {
// do some xml stuff, settings header etc
return $http({
method: 'POST',
url: URL,
headers: headers,
data: data
});
},
getSomeData: function (data) {
return this.generalWebServiceProxy('WSName', data, true);
}
}
}]);
And have the controller as is and update the $scope variable within success block.

How to return a value from a service in angular js?

I know that the data is coming from the server (I have unit tests and have seen the data in the debugger in chrome) but I can't figure out how to return the data from the angular service to the angular controller.
Service:
UPDATED
surchargeIndex.service('customerService', [
'$http', function ($http) {
this.getTest = function () {
return $http({
method: "GET",
url: "api/Customer/GetTest",
})
.success(function(data) {
return data;
});
};
}
]);
Controller:
surchargeIndex.controller('SurchargeIndexController', function ($scope, customerService, templateService) {
$scope.customers = customerService.getTest();
});
Data has the array from the server so the array is populated in the service. So to reiterate the data is there; however, I receive a 404 error INSIDE of the success handler during debugging.
What am I missing?
$http works asynchronously; fortunately it returns a promise which will be fulfilled when the response retrieved from the server. So you should return $http's get method and use returned promise to handle data.
this.getTest = function () {
return $http({
method: "GET",
url: "api/Customer/GetTest",
})
.success(function(data) {
return data;
})
.error(function() {
alert("failed");
}); // This returns a promise
};
Then in your controller you should use that promise to retrieve the expected data.
surchargeIndex.controller('SurchargeIndexController', function ($scope, customerService, templateService) {
//Use the returned promise to handle data, first parameter of the promise is used for successful result, if error happens, second parameter of the promise returns the error and you can do your error handling in that function
customerService.getTest().then(function(customers){$scope.customers = customers;}, function(err){console.error(err);})
});
You need to define a Callback to get your data "back" to your controller, after an async http call... There are different ways to do... I will show you one way without a callback, or a promise, but the best way would be to use a callback, or promise...
Wild West Way:
app.controller('myCTRL', function($scope, myService) {
$scope.valueWanted = myService.valueWanted;
myService.getData();
});
app.service('myService', function($http) {
var myThis = this;
this.valueWanted = "";
this.getData = function () {
$http.get('api/Customer/GetTest').success(function (data) {
myThis.valueWanted = data.valueWanted;
});
};
});

Categories