ionic; javascript return after .then - javascript

communicating with a REST service in ionic, I'ld like to have functions similar to this
function ListCategories_Request(){
rqst=_BuildRequest("ListCategories");
rqst.Data={extraParam1:1,
extraParam2:2
}
return $http({...ValidParameters including the rqst...}).then(GetResult,Request_onError)
}
For each function of the REST-Service, I would build a similar java-script function.
Now, as the sent request is unique, the received result needs to be handled unique, too. The REST-Service-Based analysis of the result is added to the .then-chain, but updating the parent class and the UI needs to happen in the parent class.
So, I would like to do calls like
ListCategories_Request().then(function(res){ UpdateCategories()});
ListFrames_Request().then(function(res){ UpdateFrames()});
The current problem is, that UpdateCategories() is called, before the result of the http-Request is analysed.
So, how do I prevent return $http(...).then(GetResult,OnError) to return, before the specific function inside GetResult is called?
Code of GetResult:
function GetResult( res){
if(res.status==200)
{
if( (res.data!=={}) && (res.data.Data!=={}) )
{
return AnalyzeResult(res.data);
}
}
};
While AnalyzeResult is like:
function AnalyzeResult(Result)
{
Func=Result.Func;
switch(Func.toUpperCase())
{
case "LISTCATEGORIES":
erg = ListCategories_Result(Result);
break;
case "LISTFRAMES":
erg= ListFrames_Result(Result);
break;
default:
erg = {};
console.log("UnKnown Result!");
}
FinalizeRequest(Index);
}
return erg;
}
So, I do not really get, where my mistake is. How do I prevent ListCategories_Request or ListFrames_Request from returning too early?
Thank you and best regards
Frank

You are better off using $q (given you are using angular anyway via ionic). That way you can use promises to do what you want to do. Here's an example that I put together to demonstrate the idea:
var app = angular.module("TestApp",[]);
app.controller("TestController", function($scope, $http, $q){
$scope.message = "Deferred Example";
var deferred = $q.defer();
function getAllPosts(extractor) {
$http.get("https://jsonplaceholder.typicode.com/posts")
.then(function(data){
console.log("Data is: ", data);
$scope.postIds = extractor(data.data);
deferred.resolve($scope.postIds);
});
return deferred.promise;
}
function extractPostIds(data) {
console.log("Exracting the data: ", data);
return data.map(function(post){
return post.id;
})
}
function squarePostIds(postIds) {
console.log("Squaring post ids: ", postIds);
$scope.squaredPostIds = postIds.map(function(id){ return id*id;});
}
getAllPosts(extractPostIds)
.then(function(postIds){
squarePostIds(postIds);
});
});
And here's the JSBin for this: https://jsbin.com/fugeyad/3/edit?html,js,output
Update: Adding some links to read about promises.
http://andyshora.com/promises-angularjs-explained-as-cartoon.html
http://www.html5rocks.com/en/tutorials/es6/promises/

Related

How can I access my data outside particular scope in Angular JS?

//declaring the module
var app = angular.module("sachin", ["ng-fusioncharts"]);
//declaring a factory
app.factory('team',function(){
return {
runs_aus : ''
};
});
app.controller("myCtrl", function($scope,$http,team){
$scope.australia=[];
$scope.total_runs_aus=0;
//fetching data from JSON
$http.get("convertcsv.json").then(function(response){
$scope.sachin_data=response.data;
angular.forEach($scope.sachin_data, function(value, key){
// manipulating data
if (value.opposition=="v Australia"){
if (value.batting_score=="-"|| value.batting_score == "TDNB" || value.batting_score == "DNB")
$scope.total_runs=$scope.total_runs;
else if (value.batting_score.substr(value.batting_score.length - 1) == "*"){
value.batting_score = value.batting_score.substr(1);
$scope.total_runs_aus+=parseInt(value.batting_score,10)
}
else
$scope.total_runs_aus+=parseInt(value.batting_score,10);
});
$scope.australia.push({ runs:$scope.total_runs_aus});
team.runs_aus=$scope.total_runs_aus;
//got final result in $scope.total_runs_aus
console.log(team.runs_aus);
//printing inside the scope(works fine)
});
console.log(team.runs_aus);
//printing outside the scope(can't access)
I am trying to access the total runs scored outside the
then(function()) of the get request
first I tried global variables in javascript
Now I tried using a factory Any help would be appreciated
You can use a service to store that data:
app.service('MyService', function() {
var self = {
'myString': 1,
'myObject': {},
'myArray': [],
'doSomething': function(param) {
self.myString = param
},
'anotherFunction': function() {
return true;
}
}
return self;
});
You just need to inject MyService on your controller and access it like MyService.myObject = something.
The important part to understand is that you are working async operations. The code continues to execute and prints your console logs even though the data has not been returned from $http.get(). Your code needs to account for this and run the code that operates on the data after its been resolved.
.then() expects a function as the parameter of the method signature. For example:
$http.get("convertcsv.json").then(function(response){
$scope.sachin_data=response.data;
}).then(function() {
console.log('Value in scope:', $scope.sachin_data);
});
or
function processData = function() {
console.log('Value in scope:', $scope.sachin_data);
};
$http.get("convertcsv.json").then(function(response){
$scope.sachin_data=response.data;
}).then(processData);
or chain multiple promises together (you must add angular's $q as a dependency):
function processData1 = function(data) {
//Create a deferred object.
var defer = $q.defer();
//Do something with data.
console.log('Value in scope:', data);
//Pass data to next promise in promise chain.
defer.resolve(data);
//Resolve data to be returned.
return defer.promise;
};
function processData2 = function(data) {
//Create a deferred object.
var defer = $q.defer();
//Do something else with data.
console.log('Value in scope:', data);
//Pass data to next promise in promise chain.
defer.resolve(data);
//Resolve data to be returned.
return defer.promise;
};
$http.get("convertcsv.json")
.then(processData1)
.then(processData2);
Please have a look at:
http://www.html5rocks.com/en/tutorials/es6/promises/
https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns
The code as is may have syntax errors as it has not been tested. Links are general reference and not specific to $q but the concepts are consistent.

Angular Promise not working

I try to get some important things like: companyid,employeeid etc. with every request that a user makes. So this has to be received before everything else is done.
After that the user receives information based on his companyid that he sets with every request (get/company/{companyid}).
The problem that I have is that the response for receiving the companyid takes to long and angular already tries to make a request to (get/company/{companyid}) obviously there is no companyid yet.
I've tried to fix this whit promise but it's not working.
Here I try to receive some important information about the user(that I do with every request) :
Service
(function () {
angular.module('employeeApp')
.service('authenticationservice', authenticationservice);
function authenticationservice($http,$location,authenticationFactory,$q,GLOBALS,$cookies) {
this.validateUser = function () {
var vm = this;
vm.deferred = $q.defer();
data = {"api_token": api_token};
return $http.post(GLOBALS.url+'show/employee/' + $cookies.get('employeeid'),data)
.success(function(response)
{
vm.deferred.resolve(response);
})
.error(function(err,response)
{
vm.deferred.reject(err);
});
return vm.deferred.promise;
}
}
})();
Routes file
(In my routes file I use the authenticationservice to set all important users variables.)
employeeAppModule.run([
'authenticationservice',
'constants',
function(authenticationservice,constants) {
authenticationservice.validateUser()
.then(function(response)
{
constants.companyid = response.result.Employee;
constants.role = response.result.Role;
constants.name = response.result.FirstName;
console.log('test');
},
function(response){
console.log('error');
});
}
]);
So the problem is that the user information is set to late and angular already goes to my homeController where he uses the companyId that is not being set yet.
Thankyou
The problem in your current code is return $http.post are having two return statement in your validateUser method. Which is returning $http.get before returning return vm.deferred.promise; & that why customly created promise doesn't get returned from your method. Though by removing first return from $http.get will fix your problem, I'd not suggest to go for such fix, because it is considered as bad pattern to implement.
Rather I'd say, you should utilize promise return by $http method, & use .then to return data to chain promise mechanism.
Code
function authenticationservice($http, $location, authenticationFactory, $q, GLOBALS, $cookies) {
this.validateUser = function() {
var vm = this;
data = {
"api_token": api_token
};
return $http.post(GLOBALS.url + 'show/employee/' + $cookies.get('employeeid'), data)
.then(function(response) {
var data = response.data;
retrun data;
}, function(err) {
return $q.reject(err);
});
}
}
To make sure that $ http return a $ promise object you need to check that the action in the controller returns a value and it is not a void action.

Multiple ajax request with promise in Angular based on array vlaues

I am implementing multiple ajax calls in sequence in angular. What I want to achieve is working fine with $.ajax but when I implemented with angular where I'm using $http for server request, it's not working. I am wondering that both are returning promise object then why it's not working properly.
Using $.ajax
shoppingList.split(",").reduce(function(resultPromise, shoppingItem) {
return resultPromise.then(function(result) {
pro = $.ajax('/items/'+shoppingItem);
return pro.then(function(res) {
console.log(result);
result.push(new Item(res.label,res.price));
return result;
});
});
}, $.when([])).then(completeCallback);
See the working fiddle - JSFiddle
Using Angular $http
function fetchDataDayWise(dateRanges,completeCallback) {
return dateRanges.reduce(function(resultPromise, dt) {
return resultPromise.then(function(resultData) {
machinePromise = getData();
return machinePromise.then(function(data) {
if(data && data.length > 0)
{
resultData = resultData.concat(data);
}
console.log(resultData);
return resultData;
});
});
}, $.when([])).then(completeCallback);
}
var dateRanges = [1,2,3,4]
function setData(data) {
console.log("data",arguments);
}
fetchDataDayWise(dateRanges,setData);
See the Plunkr
You can see in console. In JSFiddle, you will get array of items while in Angular plunkr it returns object. I guess it's promise object.
Any help would be appreciated.
In your service you use $http.get, this returns a promise which is the object you are seeing, to get your values from it you need to have (in your case):
deferred.resolve(data.data);
instead of
deferred.resolve(data);
Hope this helps. If you have any more questions i'll be happy to answer them.
Update:
This isn't for your code exactly, but it will give you an example of how to achieve sequential calls.
var prevPromise = $q.resolve();
prevPromise = prevPromise.then(function() {
this.someValue= value; //array of databases containing queryresults
return this.function(req, res);
}.bind(this));
I have forked your plnkr hope this will help
http://plnkr.co/edit/VWJMNU?p=preview
function fetchDataDayWise(dateRanges, compleCallback) {
var arrPromise = [];
dateRanges.reduce(function (dt) {
arrPromise.push(getData());
});
$q.all(arrPromise).then(compleCallback);
}

Cache server response (AngularJS, deferred)

I'm trying to create an angular js service that will fetch data from the server if update needed or return cached array if there is no update. In both cases service should return a promise. Service code:
getLikesForMe = function() {
var defer = $q.defer(), prom = defer.promise;
if (angular.isUndefined(this.likesForMe) ||
updateStatus.likesForMe === true) {
var that = this;
prom = $http.get(API_URL + 'likes-to.json')
.then(function(result){
updateStatus.likesForMe = false;
that.likesForMe = result.data;
});
} else {
defer.resolve(this.likesForMe);
}
return prom;
}
Current controller code:
MainUser.getLikesForMe().then(function(result) {
$scope.likesList = result;
});
Prefered controller code:
$scope.likesList = MainUser.getLikesForMe();
But currently it only works after second function (getLikesForMe()) call, on the first - the list is empty and the "result" variable is undefined.
I'm new to deferred objects and my english is pretty poor, but I hope you understand where the mistake is. Thanks a lot!
You have 2 issues
On the first call, the promise you return will be resolved with undefined as you're not returning anything from the then success callback from your call to $http.get. If you return that.likesForMe from that callback, I suspect it will work as you expect. You should probably read up on chaining promises. (Shameless plug: I wrote a blog post on AngularJS promises which contains sections on chaining)
The code is quite complicated for what it does, and you almost-never have to create a promise via $q.defer() if all you're doing to working with existing promises. It usually makes things more complicated and harder to deal with errors. You can also use $q.when() to create a promise from a non-promise value. So I propose something like
getLikesForMe = function() {
var that = this;
var useCache = !updateStatus.likesForMe && !angular.isUndefined(this.likesForMe);
return useCache ? $q.when(that.likesForMe) : $http({
method: 'GET',
url: API_URL + 'likes-to.json'
}).then(function(results) {
updateStatus.likesForMe = false;
that.likesForMe = results.data;
return that.likesForMe;
});
});
You could also read up in the docs for $http cache to see if you could come up with a solution that uses it.
If you prefer the later version of the controller code then you can't return a promise from the service.
You could return an empty object that would be augmented when you got back from the http call.
You'd then have to issue a $rootScope.$apply() so your controller is notified.

angularjs - $http reading json and wait for callback

I am trying to read data from json and wait until data will be fetched into $scope.urls.content. So I write code:
$scope.urls = { content:null};
$http.get('mock/plane_urls.json').success(function(thisData) {
$scope.urls.content = thisData;
});
And now I am trying to write something like callback but that doesn't work. How can i do that? Or is there any function for this? I am running out of ideas ;/
Do you mean that ?
$http.get('mock/plane_urls.json').success(function(thisData) {
$scope.urls.content = thisData;
$scope.yourCallback();
});
$scope.yourCallback = function() {
// your code
};
You want to work with promises and $resource.
As $http itself returns a promise, all you got to do is to chain to its return. Simple as that:
var promise = $http.get('mock/plane_urls.json').then(function(thisData) {
$scope.urls.content = thisData;
return 'something';
});
// somewhere else in the code
promise.then(function(data) {
// receives the data returned from the http handler
console.log(data === "something");
});
I made a pretty simple fiddle here.
But if you need to constantly call this info, you should expose it through a service, so anyone can grab its result and process it. i.e.:
service('dataService', function($http) {
var requestPromise = $http.get('mock/plane_urls.json').then(function(d) {
return d.data;
});
this.getPlanesURL = function() {
return requestPromise;
};
});
// and anywhere in code where you need this info
dataService.getPlanesURL().then(function(planes) {
// do somehting with planes URL
$scope.urls.content = planes;
});
Just an important note. This service I mocked will cache and always return the same data. If what you need is to call this JSON many times, then you should go with $resource.

Categories

Resources