I have a reactJS application where I am trying to validate some user input against a database value. The database is stored on AWS so I am using a fetch to a Web API that I wrote. This is the code that I am executing:
passString = "003" + newValue;
console.log("call function with ", passString);
var returnedValue = mqRequest(passString);
console.log("return from fetch with ", returnedValue);
if (returnedValue != newValue) {
localPlanID.message = "The Plan ID you entered was not found on our system";
localPlanID.css = "textbox4Bytes input-box-error";
}
The value of the variable newValue is VSTA
The code will call a function called mqRequest that is in a separate file. I include this by using this line of code:
import {mqRequest} from '../functions/commonFunctions.js';
The code of the function looks like this:
export function mqRequest (passedData) {
//var url = "https://webaccuapi-dev.accurecord-direct.com/api/homepage?mqRequest=" + passedData;
var url = "http://webaccuapi-dev.accurecord-direct.com/api/homepage?mqRequest=" + passedData;
const options = { method: 'GET' };
var returnString = "";
fetch(url, options)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
if (myJson == undefined)
{
returnString = "fetch failed";
}
else
{
returnString = myJson[0].return_response;
console.log("from function, myJson[0] = ", myJson[0]);
}
});
console.log("from function, after fetch, returnString = ", returnString);
return returnString;
}
When I execute the code, this is what I see in the console.log:
call function with 003VSTA
from function, after fetch, returnString =
return from fetch with
from function, myJson[0] = {return_response: "VSTA", return_code: "0", return_plan_name: "N/A", return_menu_string: "N/A"}
So, it appears that I am calling the function and passing it 003VSTA. The function picks up this value, builds the url variable, and executes the fetch. The fetch returns myJson[0].return_response with a value of VSTA which is correct!
The problem that I am having is, I think, a timing issue. I believe the function is called but the code is continuing to execute even though the function and fetch have not finished executing. How do I get the code to wait for a value to be returned by the function before continuing?
Thanks.
The timing issue is due to the fact the fetch call is asynchronous.
To resolve your timing issue, there are a couple of approaches. A popular one is to use Promises for the job. Here's how:
First, you need to tweak the "mqRequest" function:
export function mqRequest (passedData) {
// ...
// Step 1: Instead of returning a String, return a Promise.
return new Promise((resolve, reject) => {
fetch(url, options)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
if (myJson == undefined) {
returnString = "fetch failed";
} else {
returnString = myJson[0].return_response;
console.log("from function, myJson[0] = ", myJson[0]);
}
// Step 2: resolve the Promise with the String
resolve(returnString);
});
});
}
Then, call it like you would call a Promise:
passString = "003" + newValue;
console.log("call function with ", passString);
mqRequest(passString).then(function(returnedValue){
console.log("return from fetch with ", returnedValue);
if (returnedValue != newValue) {
localPlanID.message = "The Plan ID you entered was not found on our system";
localPlanID.css = "textbox4Bytes input-box-error";
}
});
This way, the mqRequest function call will wait for the returned data instead of continuing with the flow of the code without the returned data.
And now your logs should execute as expected.
Related
I will try to keep my problem as simple as possible, I have this function that I created:
get_total_by_status(status: string){
const total = imports.index(status).then((d) => {
return d.total
})
return total
}
and I'm calling this function like this:
var status_published = this.get_total_by_status("pending payment")
but it's not working, I have put a console.log(total) inside the function, and I got this:
Promise {<pending>}
[[Prototype]]:Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: 202
how can I return the 202 value??
I know that there are tons of questions similar to this one, and basically, all of them tell me to add async() at the function, and a await on the moment I call the function, I have tried this without success, and I have no idea what I'm missing here, I'm a python programer with 0 knowledge in react
Edit:
Tried this approach, still can't return the value
get_total_by_status(status: string, onSuccess) {
imports.index(status).then(
(d) => {
onSuccess(d.total);
}
);
}
# STUFFF
const status_published = this.get_total_by_status("published",
(response) => {
return response //also tried status_published = response
})
if I place a console.log(response) I do indeed can log the 202 that I was expecting, but status_published keeps being null
There are two options.
Option 1. Wrap your get_total_by_status call in an async function and await your get_total_by_status to get resolved value as follows:
async function get_total_by_status(status) {
const total = imports.index(status).then(
(d) => {
return d.total;
}
);
return total;
}
async function getPromiseValue() {
let status_published = await get_total_by_status("My status");
console.log(status_published);
}
getPromiseValue(); // prints "My status"
Option 2. Another option would be pass callback to your get_total_by_status function as an argument and call that callback in .then() block as follows:
function get_total_by_status(status, onSuccess) {
// you don't need to store any return value in this case
imports.index(status).then(
(d) => {
onSuccess(d.total);
}
);
}
get_total_by_status("My status", (response) => {
console.log(response); // prints "My status"
});
Let me know if you have any kind of query or doubt regarding above code snippets :)
I have this React project template, it uses Spring for backend and a PostgreSQL database.
Here, I have the name of a caregiver, and what i want, is to get the id of that caregiver.
I don't know how to retrieve the id, from the findCaregiver method. When in the function, "result.id" will show the correct id, but when it returns to "handleSubmit", the initial method, the value is gone. I tried storing it in the current components' state, in a global variable, even in localStorage. But nothing works, after the function is done, the value is gone. Any ideas? Thank you!!
handleSubmit() {
let name = this.state.formControls.caregiverName.value;
let c = this.findCaregiver(name);
console.log("id: " + c);
findCaregiver(name) {
return API_USERS.getCaregiverByName(name, (result, status, error) => {
if (result !== null && (status === 200 || status === 201)) {
console.log("Successfully found caregiver with id: " + result.id);
//result.id shows correct id here!
} else {
this.setState(({
errorStatus: status,
error: error
}));
}
});
}
getCaregiverByName is asynchronous. When you call it, the gears are set in motion, but then the function finishes immediately. Then you return to handleSubmit, and log out nothing, because it isn't done yet.
Some time later, the get finishes, and the callback function will be called. Any code that you need to run when the result is ready needs to be done in that callback, or something called by that callback.
So if we're sticking with callbacks, you can add a callback to findCaregiver:
handleSubmit() {
let name = this.state.formControls.caregiverName.value;
this.findCaregiver(name, (id) => {
console.log("id: " + id);
});
}
findCaregiver(name, callback) {
API_USERS.getCaregiverByName(name, (result, status, error) => {
if (result !== null && (status === 200 || status === 201)) {
callback(result.id);
}
}
}
If you perfer promises to callbacks (most people do), you can instead change your code to return a promise. Perhaps getCaregiverByName could be modified to return a promise, but if you don't have access to that code you can wrap your existing code in a promise like this:
handleSubmit() {
let name = this.state.formControls.caregiverName.value;
this.findCaregiver(name)
.then((c) => {
console.log("id: " + c);
});
}
findCaregiver(name) {
return new Promise((resolve, reject) => {
API_USERS.getCaregiverByName(name, (result, status, error) => {
if (result !== null && (status === 200 || status === 201)) {
resolve(result.id);
} else {
reject(error);
}
})
});
}
And if it's returning a promise, you have the option to use async/await:
asycn handleSubmit() {
let name = this.state.formControls.caregiverName.value;
const c = await this.findCaregiver(name);
console.log("id: " + c);
}
I refactored my code have cleaner code without duplication. But I'm wondering if the use of $q.all is the best option in my scenario...
Code logic:
I have an "optional" promise. In 1 scenario I need to call an external API (= promise), in the other scenario, I don't need that external call (= no promise).
So I created a variable in which I can store the promise (or null for the scenario without promise).
$q.all waits for the promise and then checks if the return value is something returned by the promise (scenario 1) or null(scenario 2).
Function before refactor
model.updateWish = function(wish) {
var defer = $q.defer();
if (wish.image) {
// Rename temporary image.public_id to wish_id
cloudinaryService.renameImage(wish.image.public_id, wish._id,
function (image) {
// Update wish with renamed image
wish.image = image;
$http.put(URLS.WISH + "/" + wish._id, wish).success(function (wish) {
updateWishlist(wish);
defer.resolve(wish);
console.info("wish updated", wish);
});
});
} else {
$http.put(URLS.WISH + "/" + wish._id, wish).success(function (wish) {
updateWishlist(wish);
defer.resolve(wish);
console.info("wish updated", wish);
});
}
return defer.promise;
}
Code after refactor
model.updateWish = function(wish) {
var defer = $q.defer();
var renamedImagePromise = null;
if (wish.image) {
// Rename temporary image.public_id to wish_id
renamedImagePromise = cloudinaryService.renameImage(wish.image.public_id, wish._id)
.then( function (image) {
// Update wish with renamed image
wish.image = image;
return wish;
});
}
// Wait until renameImagePromise is resolved and send updated wish to server
$q.all([renamedImagePromise]).then(function(wishWithRenamedImage){
if (wishWithRenamedImage[0]) { // $q.all returns an array, wish is in "wishWithRenamedImage[0]"
wish = wishWithRenamedImage[0];
}
$http.put(URLS.WISH + "/" + wish._id, wish).success(function (wish) {
updateWishlist(wish);
defer.resolve(wish);
console.info("wish updated", wish);
});
})
return defer.promise;
}
Both functions work, but I'm wondering if this is the best implementation for my requirements...
Use $q.when and also avoid the deferred anti-pattern:
model.updateWish = function(wish) {
̶v̶a̶r̶ ̶d̶e̶f̶e̶r̶ ̶=̶ ̶$̶q̶.̶d̶e̶f̶e̶r̶(̶)̶;̶
var renamedImagePromise = null;
if (wish.image) {
// Rename temporary image.public_id to wish_id
renamedImagePromise = cloudinaryService.renameImage(wish.image.public_id, wish._id)
.then( function (image) {
var wishClone = Object.assign({},wish);
// Update wish clone with renamed image
wishClone.image = image;
return wishClone;
});
};
// Wait until renameImagePromise is resolved and send updated wish to server
return $q.when(renamedImagePromise).then(function(wishWithRenamedImage){
var wishToPut = wishWithRenamedImage || wish;
return $http.put(URLS.WISH + "/" + wish._id, wishToPut)
.then(function (resolve) {
var wish = resolve.data;
updateWishlist(wish);
̶d̶e̶f̶e̶r̶.̶r̶e̶s̶o̶l̶v̶e̶(̶w̶i̶s̶h̶)̶;̶
console.info("wish updated", wish);
return wish;
});
});
̶r̶e̶t̶u̶r̶n̶ ̶d̶e̶f̶e̶r̶.̶p̶r̶o̶m̶i̶s̶e̶;̶
};
Update
Out of an abundance of caution, I modified the code to clone the wish object. When an object reference is passed to a JavaScript function, that function can mutate that object. With functional programming best practices, mutating objects should be avoided.
I am unable to do the promise looping.
I make a service call to get list of providers, then for each provider, I make another service call to get a customer.
A provider has 1 or more customers. So eventual list of customer is to be decorated and displayed.
In other format I am trying to achieve:
*serviceA.getProvider(){
foreach(providers){
foreach(provider.customerID){
serviceB.getCustomer(customerId)
}
}
}
.then(
foreach(Customer){
updateTheCustomer;
addUpdatedCustomerToAList
}
displayUpdatedCustomreList();
)*
I have written following code, that isn't working
doTheJob(model: Object) {
let A = [];
let B = [];
let fetchP = function(obj) {
obj.Service1.fetchAllP().then(function (response) {
let P = cloneDeep(response.data);
_.forEach(P, function(prov) {
_.forEach(prov.CIds, function(Id) {
A.push(Id);
});
});
_.forEach(A, function(CId) {
return obj.Service2.getById(CId);//what works is if this statement was: return obj.Service2.getById(A[0]);
//So, clearly, returning promise inside loop isn't working
});
})
.then(function(response) {
B.push(response.data); //This response is undefined
angular.forEach(B, function (value) {
obj.updateAdr(value)
});
obj.dispay(B);
});
};
fetchP(this);
}
forEach don't stop when you use return inside of it, try to use a plain loop instead, why you don't just loop with for ?
_.forEach(A, function(CId) {
return obj.Service2.getById(CId);
}
as stated by #Ze Rubeus if you return inside a callback within a for loop that value will be lost, since it's not returned to the caller.
probably you wanted something like this
return Promise.all(A.map(function(CId){
//collect each promise inside an array that will then be resolved
return obj.Service2.getById(CId);
})
Hi I am developing one web api with angularjs application. I am doing file upload module. I am facing problem in returning object once file upload is finished.
Below is my api code to save file related data to database and if it is succsfull I am returning object.
NCT_FileUpload obj = new NCT_FileUpload();
obj.file_path = uploadPath;
obj.user_id =9;
entityObject.NCT_FileUpload.Add(obj);
int result = entityObject.SaveChanges();
if (result == 1)
{
return Request.CreateResponse<NCT_FileUpload>(HttpStatusCode.OK, obj);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "1");
}
This is my angularjs code.
$scope.uploadFiles = function () {
$scope.uploading = true;
uploadService.uploadFiles($scope)
// then() called when uploadFiles gets back
.then(function (data) {
// promise fulfilled
$scope.uploading = false;
if (data === '') {
alert("Done!!!")
$scope.formdata = new FormData();
$scope.data = [];
$scope.countFiles = '';
$scope.$apply;
} else {
alert("Shit, What happended up there!!! " + data);
}
}, function (error) {
$scope.uploading = false;
//Server Error
alert("Shit2, What happended up there!!! " + error);
}
);
};
Below is my service code in angularjs
if (typeof response.data === 'string') {
return response.data;
} else {
return $q.reject(response.data);
}
Here i want to check with object and not as string.
I am able to save data in server, If i put below code in api controller i am able to display done. But i am returning object so my data will not be empty. Currently my error function is executing. I want to handle object returned from api in success function. Is there any way to do this? Any help would be appreciated. Thank you.
return new HttpResponseMessage(HttpStatusCode.OK) ;
I think the problem here is the generic parameter. Change this:
return Request.CreateResponse<NCT_FileUpload>(HttpStatusCode.OK, obj);
To this:
return Request.CreateResponse(HttpStatusCode.OK, obj);