Return data from service in time - angularjs

I have a factory, which is returning a ngResource
.factory('web'... {
return $resource(URL, null, {
create: {method: 'POST'}
}
}
then I have a service which needs to get data from the above factory only if a URL param changed, or if the variable where I store the response is empty.
var query = Web.get(param);
query.$promise.then(function(res) {
variable = res;
}
return variable
Then I call the above service, to get some data, if variable is empty, make a request, else return variable.
The problem is that because of the request I don't get any data, how can I fix this? Also I would like to get the value of response not a promise.
UPDATE:
Why I don't need a promise.
At one point I will have all the data that I need, so I don't have to make request on Web. So from an array of objects, the user will be able to select one object, and then the variable from above will have the value of the selected object.
Now my function will return an object instead of a promise, I guess I can check the return type, but I hoped there is another way.

At the time your function returns the promise hasn't resolved so you always get undefined returned.
You should return the promise to your calling function and let that wait for the promise to resolve or handle any errors.
var query = Web.get(param);
return query.$promise;
The problem is that because of the request I don't get any data, how can I fix this? Also I would like to get the value of response not a promise.
Unless I'm very much mistaken, you can't.
UPDATE based on updated question
You still need a promise to do what you want. Its not too difficult to difficult to wrap it all up.
function getData(param)
{
va deferred = $q.defer();
if (variable){
// Already got what we need
deferred.resolve(variable);
}
else
{
// Lookup the data
var query = Web.get(param);
query.$promise.then(function(res) {
variable = res; // Save for later
deferred.resolve(variable);
},
function(err){
deffered.reject(err);
});
}
return deferred.promise;
}

Related

AngularJS: Declaring unique variable inside interceptor

I have a need to have a variable that is unique per request inside my http interceptor. So when the request comes in I want to set this variable to some value and read that value on the response. The issue is that the interceptors are shared so every time a new request comes in my variable will just be overridden.
angular.module('app').factory('httpInterceptor', ['$q',
function($q) {
var myInstanceVar = "";
return {
request: function (config) {
myInstanceVar = Math.random();
return config;
},
response: function (response) {
console.log(myInstanceVar);
return response || $q.when(response);
}
}
}
]);
So in this example, I would want myInstanceVar to be unique when I output the value in response but instead it just outputs the value that was generated the last request. So if I have 3 requests the output would be 3,3,3 instead of like 5,9,3 since the last request set it to 3.
I know I could probably just append the value to the request body and have the server return it back but I want to avoid that if possible.
I am using AngularJS 1.6.4 if that matters.
You can store the variable in the config, and get it back in response.config.

Use response from one $http in another $http in Angularjs

First of all I want to use $http in order to receive some data (e.g. students), then I want to make another $http call to get e.g. studentDetails. After that I want to append some part of studentDetails to students JSON.
Also I need response from the first call in order to create the url for the second call.
Problem is that I cannot access response of the first http call inside the another.
Does anybody know how this can be done?
var getStudents = function(){
var deferred = $q.defer();
$http.get("https://some_url")
.success(function(response){
deferred.resolve(response);
}).error(function(errMsg){
deferred.reject(errMsg);
});
return deferred.promise;
}
var appendStudentDetails = function(){
getStudents().then(function(response){
var studentsWithDetails = response;
for(var i=0; i<studentsWithDetails.length; i++){
$http.get("some_url/"+studentWithDetails[i].user.details+"/")
.success(function(res){
//here I want to append the details,
//received from the second http call, to each student
//of the array received from the first http call
//PROBLEM: I cannot access response of the
//first http call inside the another
})
}
})
You're using the deferred anti-pattern as well as the deprecated success/error-callbacks. You should instead use then, since it returns a promise, and you can chain promises.
Here's an example of how you could do it:
function getStudents(){
return $http.get('[someurl]');
}
function appendStudentDetails(studentsWithDetails){
for(var i=0; i<studentsWithDetails.length; i++){
appendSingleStudentDetails(studentsWithDetails[i]);
}
}
function appendSingleStudentDetails(singleStudent){
$http.get("some_url/"+singleStudent.user.details+"/")
.then(function(res){
// Append some stuff
singleStudent.stuff = res.data;
});
}
// Call it like this:
getStudents()
.then(function(response){ return response.data; })
.then(appendStudentDetails);
I decided to structure the appendStudentDetails function a little differently, based on its name, but you could as easily just call getStudents() within the method as you did before.
Beware not to use the i-variable inside your inner then-function, as that would cause you troubles with closure.
Edit: Fixed example to avoid problem with i being under closure.

ReactJS actions not loading data through ajax call

I have a requirement wherein I need to load the data through an ajax call to server and then pass on the data to reducer to render my page through props.
But I see the data in the ajax call is being shown as undefined.
function getInitData(url) {
axios({url: url, timeout: 20000, method: 'get', responseType: 'json'})
.then(function(response) {
console.log(response.data.results)//--DATA DISPLAYED
return response.data.results
})
.catch(function(response) {
console.error(response.data);
})
}
let formActions = {
loadInitJSONSchema: function(formSchema) {
let dataLoaded = getInitData('/startInterview')
console.log(dataLoaded);//--DATA DISPLAYED as UNDEFINED
return {type: 'LOAD_INIT_JSON_SCHEMA', formSchema: dataLoaded}
}
}
I dont know why my data displayed as undefined in my actual method may be it is because of the asynchrnous call?? If so how do I load my data in actions??
Please find the complete code at the URL
It's promises all the way down.
A jQuery example: jQuery('body') does not return the body element. It returns a jQuery collection. jQuery('body').css('background', 'red'); also returns a jQuery collection. It's collections all the way down.
axios.get().then(function(response) { return response; }) does not return response. It returns a promise.
First, change this, to return the promise:
function getInitData(url) {
return axios...
Then change your function:
loadInitJSONSchema: function(formSchema) {
return getInitData('/startInterview').then(function(data) {
return {type: 'LOAD_INIT_JSON_SCHEMA', formSchema: data}
})
Then anyone who uses loadInitJSONSchema gets the promise and gets the value in a .then().
loadInitJSONSchema(schema).then(function(result) { ... do something with result })
It's promises all the way down.
This flow is asynchronous. With var something = axios.get().then(function(response) { return response; }) the code is evaluated in place and the program keeps going. The .then() callback happens at a later time, long after the current function has finished executing.

Angular storing server data in a global service. How do I ensure it is there

I have a globalDataService in my app that reads a couple of entities from the server.
I only want to read the data once, and then serve it up via a method on the service. Here's a simplified version
angular.module("myApp").factory("globalData", ["siteResource", globalData]);
function globalData( siteResource) {
var sites = [];
siteResource.query().$promise.then(function(data){
sites = data;
},
function(response) {
//handle bad stuff
});
var getSites = function () { return sites; }
return { getSites: getSites };
}
and in my controller I just want to be able to do this
this.sites = globalData.getSites();
and know that the data is there, and if it isn't then something is wrong. What do I need to do in my service to make this happen, I've just wasted 2 hours trying to do something with $q but with no joy.
It's pot luck whether the globalData service has loaded the data or not when I need it, particularly when the app first loads....
Save the promise and return the promise. Create the promise once and reuse it.
angular.module("myApp").factory("globalData", ["siteResource", globalData]);
function globalData(siteResource) {
var promise;
function getSitesPromise () {
if (!promise) {
promise = siteResource.query().$promise;
promise = promise.catch( function (error) {
//handle bad stuff
});
};
return promise;
};
return { getSitesPromise: getSitesPromise };
}
What your are doing is pretty simple.
Prob making $http requests to your server to get data. But you don't want to make them every time just on init.
you can use $q like this ...
var promise1 = $http.get('/mypath1');
var promise2 = $http.get('/mypath2');
var promises = $q.all([promise1, promise2]); // resolves when all promises are resolved OR will reject when ONE promise rejects
promises.then(function(arrayContainingAllServerResponses) {
// do something
}).catch(function(error) {
// oops one of the requests failed
})
sorry but i dont have time for more detail - this might get you on the right track - cheers
this works because $http returns a promise :)
Remember if your have a promise then you can call THEN on it - the THEN code will be executed when the promise is resolved (not immediately). You can even chain THENs by returning a promise from a THEN. Hope this all helps.
If a method returns a promise then you can call THEN on its return value. REMEMBER $http returns a promise which is resolved or rejected when your server responds or the request times out!

How is result passed from $http to the .onsuccess function?

How is result passed from the $http object to the unnamed function that is executed on success?
$http
.success(function (result) {
...
})
I know that the result is passed via any variable name that i put into the function. It is typically called result. But how is this done? It seems like wizardry to me.
I would expect to have to write something like:
$http
.success(function (result=$http.result) {
...
})
You have to study how both Javascript Function Paramters and Promises work.
The code that you pasted comes, I Think, from some AngularJS Application.
If my assumption is correct, $http is a service and doesn't have anyone success method.
The success method is present on $http methods:
//get, post, ecc...
$http.get(...).success()
By the way:
Javascript doesn't provide any way to match parameters, their order is always the order provided by the callee and the names that you use is just for you (Don't confuse with the IOC that the DependencyInjection in AngularJS does). EXAMPLE 1
function loggerCase1(log1, log2, log3, log4) {
console.log('loggerCase1 => param-1:', log1);
console.log('loggerCase1 => param-2:', log2);
console.log('loggerCase1 => param-3:', log3);
console.log('loggerCase1 => param-4:', log4);
console.log('---------------------');
};
function loggerCase2(log4, log2, log1, log3) {
console.log('loggerCase2 => param-1:', log4);
console.log('loggerCase2 => param-2:', log2);
console.log('loggerCase2 => param-3:', log1);
console.log('loggerCase2 => param-4:', log3);
console.log('---------------------');
};
function loggerCaseN() {
for(var i = 0; i < arguments.length; i++) {
console.log('loggerCaseN => param-' + (i + 1) + ': ', arguments[i]);
}
console.log('---------------------');
};
var logs = ['log1', 'log2', 'log3', 'log4'];
loggerCase1.apply(this, logs);
loggerCase2.apply(this, logs);
loggerCaseN.apply(this, logs);
If it's all clear about function parameters behaviour in javascript... you will know that isn't possibile to say give me the first as the second or something like that, also, the example that you pasted seems similar to default parameters (implemented in ES6, aka Javascript Harmony).
Let's go to the point 2:
In a simple promise chain (find on google or see the link above) you can pass a result to the next callback using return. EXAMPLE2
angular
.module('promisechainging', [])
.run(function($q) {
$q
.when('Hello World')
.then(function(greetings) {
console.log('ring 1', greetings);
return greetings;
})
.then(function(salut) {
console.log('ring 2', salut);
return salut;
})
.then(function(ciao) {
console.log('ring 3', ciao);
return { message: ciao };
})
.then(function(result) {
console.log('ring 4', result.message);
return result;
})
.catch(function(error) {
console.log('THIS LOG NEVER HAPPENS BECAUSE THERE AREN\'T REJECTED PROMISES');
return $q.reject(error);
})
.finally(function() {
console.log('We Are At The END');
})
;
})
;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="promisechainging"></div>
Basically is not important how parameters are named!
Angular is using the promise mechanism which basically returns an object that let you know when the result is available or an error has been thrown.
When the ajax call returns, angular is calling the promise and providing the result as a parameter.
It's just like calling a regular function.
$http allows you to perform async network operations and returns a promise object (you can read more about promises in Angular here).
The success and error methods were used to declare callbacks to what happens when the promise is resolved (when the request was successfully completed) or rejected (when there was an error at processing the request). I used the past tense since they are now deprecated and the desired way to handle these is using the then method of the promise object.
// 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.
});
Basically, the syntax is pretty much the same - the successCallbackFunction has the same signature as the method you were passing in the success method of your example.
But this is only the method signature. Your callback function parameters can be called however you want (result, data etc). All you have to keep in mind is that the first parameter in your callback function is going to be the data returned by your request.
$http
.success(function (result) {
...
})
$http will return a Promise Object which is nothing but a Javascript Object with success and different other functions.
So the statement immediately becomes like below as $http is evaluated,
(Promise Object)
.success(function (result) {
...
})
The success function of promise will save this anonymous function to be called once the promise is resolved. We can manually resolve promises, but I guess http will do this for you here.
Once http request(AJAX) is successful angular will tell this Promise object to run this success function by resolving the Promise, somewhat like:
suceess: function(responseData){ //success of AJAX
resolve(responseData); //this will pass the result to promise
}
Once resolve is called promise object has the result with it, it will then call the success function you passed initially with this value of result.
PS: This is a rough idea, I ave to look into Angular source to see their actual implementation.
Javascript functions are also class objects.
When $http completes it will call either the success or fail function - they are objects so they can be passed around. When it does, it will provide the parameters.

Resources