angularjs promise not resolving properly - javascript

My controller has all the required dependencies injected.
$scope.connect = function(url) {
var defer = $q.defer();
var promise = $http.get(url).then(function (response) {
$timeout(function(){
defer.resolve(response);
},10000);
defer.resolve(response);
$scope.$apply(); //$rootScope.$apply();
});
return defer.promise;
};
$scope.mymethod = function(){
$scope.globalMydata[];
console.log("before the http get");
$scope.connect("MY_URL").then(function(data) {
console.log("called!", data);
console.log("INSIDE the http get");
$scope.mydata = data;
//$scope.globalMydata.push(data);
});
console.log("after the http get ");
//do some processing of the returned data here
var dataHolder = $scope.mydata;
return calculatedValue;//value from procesing
}
When the code is executed "INSIDE the http get" is invoked as the last debug log. I get the results from the get call but since its returned later, I am unable to do any processing with it. This is the exactl reason why we promises right? I need the promised data to do some processing inside the controller.
Any issue in my promise implementation??

I'm not sure whether I get your question, but it looks like you've built a promise interseptor, but from your question it looks like you want just the regular promise behaviour. So I'll try that..
I'm not an angular expert but I do use $http promises a lot and here's how I do it.
I register the $http call as a service, like this:
app.service('ajax',function(host,$http){
this.post = function(api,data,cb){
$http.post(host + api,data).success(cb)
};
this.get = function(api,cb){
$http.get(host + api).success(cb)
}
});
host is a predefined module.value. I inject this service into every controller that needs to call http requests and operate them like this:
ajax.post('users', UserToken, function(data){
console.log('Users points: ' + data.points)
})
As I understand $http has promises built in, so there's no need for q and defere, it's all done at the background. ajax.post calls the service, which sends data to host + 'users', server-side looks for user by his token and return some data with one key by the name of points with a value of the users points. Client-side: upon successful reply from the server it proceeds to the cb function which then console logs the user points.
So I can do whatever modification I need to the promise inside that cb function, since it is not called before a successful reply from the server.
The success and error methods have a few more optional arguments, check them out here.

Related

Return promise from service for locally stored data in angular

I have some config data for my app that is stored on my API server (form.io in this case), and since it will be rarely changed, I want to store it in localStorage and then update it as needed. So in my getStationConfig service, I check for the data in localStorage, and if it's not there, get it from the API and store it locally for next time.
The issue is returning the data from localStorage in a promise so my controller code that is expecting a promise can handle it. The code to get the data from my controller is this:
var stationPromise = shiftService.getStationConfig().then(function(data) {
vm.configSlots = data;
});
and my service looks like this:
var getStationConfig = function() {
// First check to see if info is stored locally.
var config = JSON.parse(localStorage.getItem('cfdConfig'));
if (config) {
return config;
}
// Get position info from appropriate Config resource submission.
// Code borrowed from ngFormioHelper.FormioAuth.
var token = localStorage.getItem('formioToken');
var config = {
disableJWT: true,
headers: {
"x-jwt-token": token
}
};
return $http.get(Formio.getAppUrl() + '/config/submission', config)
.then(function(result) {
// Code goes here to format the data for return to the controller
// Now that it's all formatted, store the info in localstorage so that it can be retrieved from there
// later and we don't have to keep hitting the API for it.
localStorage.setItem('cfdConfig', JSON.stringify(allSlots));
return allSlots;
},
function(err) {
console.log(err);
});
};
As is is written, the data that is returned from localStorage (the config var at the top) is in the same format as allSlots at the bottom, but it's not in a promise, so the controller doesn't like it. How can I wrap or return it so that it's in a promise? Do I need to just call localStorage via $http.get() (if that's possible)? Or another way?
Thanks.
Inject $q promise service into your service and use it to return the data wrapped in a promise
if (config) {
return $q.resolve(config);
}

How to get currently logged in user details from Promise object in jhipster based application

I am trying to create 'Order' object in the front end and pushing it into the database using REST services. POJO of 'Order' looks like below
#NotNull
#Field("total")
private BigDecimal total;
#Field("status")
private String status;
#Embedded
public User user;
Now I have a 'Principal' service which is providing information of the currently logged in user.I have tried 'console.log(Principal.identity())' which is returning result as shown below. Here 'User' data is present inside the '$$state' Object.
I am not able to find out how to take 'user' data from promise object and add to the 'Order' object. I have dirty method to get user data by digging inside the Promise object as shown below but I am skeptical about this method.
What is the correct way to get data from Promise in this scenario?
EDIT:
This is jhipster based application. Below is the "Principle" service code
'identity: function (force) {
var deferred = $q.defer();
if (force === true) {
_identity = undefined;
}
// check and see if we have retrieved the identity data from the server.
// if we have, reuse it by immediately resolving
if (angular.isDefined(_identity)) {
deferred.resolve(_identity);
return deferred.promise;
}
// retrieve the identity data from the server, update the identity object, and then resolve.
Account.get().$promise
.then(function (account) {
_identity = account.data;
_authenticated = true;
deferred.resolve(_identity);
Tracker.connect();
})
.catch(function() {
_identity = null;
_authenticated = false;
deferred.resolve(_identity);
});
return deferred.promise;
}'
Here is the jhipster generated method to receive resource from server using ngResource.
'angular.module('hotSpiceApp')
.factory('Order', function ($resource, DateUtils) {
return $resource('api/orders/:id', {}, {
'query': { method: 'GET', isArray: true},
'get': {
method: 'GET',
transformResponse: function (data) {
data = angular.fromJson(data);
return data;
}
},
'update': { method:'PUT' }
});
});'
The Principal.identity() function returns a Promise. First read what is promise.
Then do something like:
Principal.identity().then(function (user) {
var data = {
// other fields
user: user
};
// do something with data only inside this inner function
});
Doing Principal.identity().$$state.value is bad not only because it related on internal implementation of angular's promises but it also won't work in all cases. Promises by nature is asynchronous and this work only because Jhipster caches result of http request which returns current user. But if there are no info about current user at time of your new requst, then Principal.identity().$$state.value will be undefined because first it need to send http request to the server and only after that this promise will be "resolved" (internally it will set the value variable and call function defined in then method).
Also I should note, that you should not pass current user from JS code to the server. You should take current user on server side (from session or something) after request arrived and set it to your model if needed. Never trust user code (code which runs in user's browser). It can inject any value to this request and send it to the server.
Can you explain the way you are retrieving the principal service? If it is returning a promise you need to set the data you want to a local variable in the "then" method.
Now to see what "Principal" service has , you can use the below code in chrome console
angular.element(document.querySelector('html')).injector().get(Principal);

Get tweets using angularjs

I am trying to make an app with material design and angularjs to get the tweets using hashtag search.
getTweets: function(hashtag, since,$http) {
var cfg = {};
var paramSince = since ? '&since_id='+ since : '';
var queryUrl = 'https://api.twitter.com/1.1/search/tweets.json?q=%23'+hashtag+paramSince;
// var queryUrl = '/search?hashtag='+hashtag+paramSince;
var promise = $http.get(queryUrl, cfg).then(function (response) {
return response;
});
return promise;
}
This API returns error 215, Bad Authentication Data
Here is the full application
STEPS TO REPRODUCE:
(i) Click Add Account
(ii)Login
(iii) Click finish
$http is undefined. You injected $http service into your twitterApp.services factory, then you (try) redeclared it inside the returned function getTweets.
In this case there is no "magic", you call getTweets with two arguments, so $http becomes undefined. The solution is removing this parameter from getTweets and use $http as a closure.
UPDATE:
There's no error handling in the process, you have to reject the promise when error occurs. This way you can also see the error comes from the server.
http://plnkr.co/edit/Lbb6EvwsjuecmFn5Vchd?p=preview
As you can see on the console, when trying to get connected, the server returns an origin error:
Error: Origin "http://run.plnkr.co/Of0F9UHpjhrqkjdw/" does not match
any registered domain/url on oauth.io(…)
It's probably about settings in your server (in this case, oauth.io) in terms of CORS.

Browser can process scripts before handle post request

Browser can process scripts before handle post request. Conside I have the following sample
if (some true condition) {
console.log("ready to post")
restangular.all.post(RequestData).then(function(response){
//some post methods
console.log("response")
});
}
//then containing scripts
cosole.log('Hello')
....
output
ready to post
Hello
response
I expect to do the POST request before printing "Hello". How to overcome this?
In order to achieve what you want you should look into angularJS promises, since the POST request is asynchronous. For example check this link:
http://www.webdeveasy.com/javascript-promises-and-angularjs-q-service/
The main idea is to first create a call that returns a deferred object, something like
this.myFunction = function (myForm) {
var deferred = $q.defer();
$http.post(myURL, myForm)
.success(function (data) {
//resolve the promise
deferred.resolve('SUCCESS');
})
.error(function (data) {
//reject the promise
deferred.reject('ERROR');
});
//return the promise
return deferred.promise;
}
and then call it like
var myPromise = this.myFunction ($scope.modalForm);
// wait until the promise return resolve or eject
//"then" has 2 functions (resolveFunction, rejectFunction)
myPromise.then(function(resolve){
// do stuff here, the post request is successfully finished
}, function(reject){
return;
});
Alternatively, any code you want to be executed after the POST request, you can put it in the success function of the request.

Angular HTTP within a HTTP Interceptor

I need to append the necessary HMAC headers to a request. This should not be very difficult however I am starting to get frustrated. What is wrong with the following code. The actual http call I am doing works; I have run this call myself and it returns the necessary data. It does not work inside the interceptor.
I merely want to get the current implementation working before I add whitelist or blacklist and other customizable data for this interceptor. This is not a question about hmac however but with promises.
The error in this interceptor is with the entire promise line starting at $http(...). When i remove this block and use it as is (minus promise execution) it works fine. As soon as i uncomment the line it gets stuck in a loop and crashes chrome. Everywhere I have read says this is how it is done, but this clearly does not work.
function requestInterceptor(config){
var $http = $injector.get('$http');
var deferred = $q.defer();
$http.get(hmacApiEndpoint, {cache: true}).then(function(data){
console.log('HMAC - Success', data)
deferred.resolve(config)
}, function(config){
console.log('HMAC - Error', config)
deferred.resolve(config)
})
return deferred.promise;
}
return {
request: requestInterceptor
};
Does this have something to do with the fact that angulars $http promise is a different implementation than that of '$q'?
It doesn't look like you are actually amending the config with the newly obtainted HMAC.
Also, you'd need to protect against your requestInterceptor intercepting the call to obtain the HMAC, thus resulting in an infinite loop.
And lastly, you don't need deferred here - just return the promise produced by $http (or $http.then()):
function requestInterceptor(config){
var $http = $injector.get('$http');
// just return, if this is a call to get HMAC
if (config.url === hmacApiEndpoint) return config;
return $http.get(hmacApiEndpoint, {cache: true})
.then(function(response){
console.log('HMAC - Success', response.data)
// not sure where the HMAC needs to go
config.headers.Authorization = response.data;
return config;
})
.catch(function(){
return $q.reject("failed to obtain HMAC");
});
}
return {
request: requestInterceptor
};

Categories