I have a function which I use to populate some fields at load, which looks like this:
function billingAddress(){
var urls = ['myURL'];
var output = [];
Promise.all(
urls.map(
u=>fetch(u).then(response => {
if (!response.ok) {
throw new Error("Http Error " + response.status);
}
return response.json();
})
)
).then(texts => {
fillAddress(texts);
var info = getCustomerInfo(texts);
console.log(info); //returns the data
output.push(info);
});
return output;
}
The fillAddress function just fills in the respective fields on document load. In order to place an order, I need to gather the customer info and send a post request to the server. What I don't understand is how I can save the information from getCustomerInfo so I can process it at a later time.
For your reference,
function getCustomerInfo(data){
var temp = data[0]['addresses']['shipping'];
var info = {};
info['address1'] = temp[0];
info['address2'] = temp[1];
info['city'] = temp[2];
info['zip'] = temp[3];
info['country'] = temp[4];
info['state'] = temp[5];
info['phone'] = temp[8];
info['gst'] = temp[9];
info['email'] = temp[10];
info['items'] = [];
return info;
}
Post function:
function placeOrder(){
var info = billingAddress();
console.log(info); //returns undefined
$.ajax({
url: 'placeOrder',
contentType: 'application/json',
type: 'POST',
dataType: 'json',
data: JSON.stringify(info),
success: function(data){
console.log(data);
}
});
}
placeOrder() is an onclick function, so I can't run it inside billingAddress()
You are getting your info data asynchronously, so you must access it asynchronously. What this means is that you can't return a value which is obtained from an asynchronous function call in a synchronous function, like you are trying to do with pushing info to output and then returning output. What is happening in your function is that output is being immediately returned as an empty array, while your asynchronous code executes in the background and then updates this array but only after it has already been returned. Instead, you should return a promise from your billingAddress function and access the data in the promise callback:
function billingAddress(){
var urls = ['myURL'];
return Promise.all(
urls.map(
u=>fetch(u).then(response => {
if (!response.ok) {
throw new Error("Http Error " + response.status);
}
return response.json();
})
)
).then(texts => {
fillAddress(texts);
return getCustomerInfo(texts);
});
}
function placeOrder(){
billingAddress().then(info => {
$.ajax({
url: 'placeOrder',
contentType: 'application/json',
type: 'POST',
dataType: 'json',
data: JSON.stringify(info),
success: function(data){
console.log(data);
}
});
});
}
Also, I would recommend using const or let instead of var and async/await to handle your promises, which will result in cleaner code:
async function billingAddress(){
try {
const urls = ['myURL'];
const texts = await Promise.all(
urls.map(u => {
const response = await fetch(u);
if (!response.ok) {
throw new Error("Http Error " + response.status);
}
return response.json();
})
);
return getCustomerInfo(fillAddress(texts));
} catch (e) {
// handle errors
}
}
async function placeOrder(){
try {
const info = await billingAddress();
$.ajax({
url: 'placeOrder',
contentType: 'application/json',
type: 'POST',
dataType: 'json',
data: JSON.stringify(info),
success: function(data){
console.log(data);
}
});
} catch (e) {
// handle errors
}
}
Related
Hi i'm using MeaningCloud's api to get the proper object back once it analyses a string of text or a url for the Natural language processing (NLP). But it doesn't return the proper object.
Right now the code returns a string with the text "[Object object]" on the HTML page. I need it to return the results of the api call which returns the proper JSON object(that I can see in the console) in a proper "key/value" pair format on the HTML page.
Here's my script:
const baseURL = "https://api.meaningcloud.com/sentiment-2.1";
const key = "Your_api_key";
const submitBtn = document.getElementById("submitBtn");
submitBtn.addEventListener("click", (e) => {
e.preventDefault();
const url = document.getElementById("url").value;
if (url !== "") {
getData(baseURL, url, key)
.then(function (data) {
postData("/add", { data: data });
}).then(function () {
receiveData()
}).catch(function (error) {
console.log(error);
alert("Invalid input");
})
}
})
const getData = async (baseURL, url, key) => {
const res = await fetch(`${baseURL}?key=${key}&txt=${url}`)
try {
const data = await res.json();
return data;
}
catch (error) {
console.log("error", error);
}
}
const postData = async (url = "", data = {}) => {
const response = await fetch(url, {
method: "POST",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
data: data
})
});
try {
const newData = await response.json();
return newData;
} catch (error) {
console.log(error);
}
};
const receiveData = async () => {
const request = await fetch('/all');
try {
// Transform into JSON
const allData = await request.json()
console.log(allData)
// Write updated data to DOM elements
document.getElementById('result').innerHTML = allData;
}
catch (error) {
console.log("error", error);
// appropriately handle the error
}
}
I have another main file that's the server.js file which I run using node server.js that renders the html page properly but the script doesn't render the results on the page properly. You can signup on meaningcloud for a free api key that has a very convenient number of calls you can make.
I am getting the error data: { success: false, error: 'Not logged in: Invalid signature' } for /wallet/balances. Interestingly, the same code runs for /wallet/coins and /markets for FTX REST API. The code is in JS
PLEASE HELP!!
const url = "https://ftx.us/api/wallet/balances"
const path = "/api/wallet/balances"
const timestamp = Date.now()
const method = "GET"
const payload = `{timestamp}{method}{url}`
const hash = CryptoJS.HmacSHA256(payload, process.env.FTX_API_SECRET)
// var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, "Secret Passphrase");
// hmac.update(JSON.stringify(timestamp));
// hmac.update(method);
// hmac.update(path);
// var hash = hmac.finalize();
const hash2 = crypto.createHmac('sha256', process.env.FTX_API_SECRET).update(payload).digest("hex")
console.log("API KEY ", process.env.FTX_API_KEY)
axios({
method: "get",
headers: {
"FTXUS-SIGN": CryptoJS.enc.Hex.stringify(hash),
// "FTXUS-SIGN": hash2,
"FTXUS-KEY": process.env.FTX_API_KEY,
"FTXUS-TS": timestamp,
},
url: url
})
.then( (response) => {
if (response.data.success) {
callback(null, response.data.result)
} else {
// error handling here for the api
callback(result.data.error)
}
})
.catch ( (e) => {
console.log("exception in request ", e)
})
add these 2 lines in headers,
{
"FTXUS-SIGN": CryptoJS.enc.Hex.stringify(hash),
"FTXUS-KEY": process.env.FTX_API_KEY,
"FTXUS-TS": timestamp,
"Content-Type": "application/json",
"Accepts": "application/json",
}
It worked for me
I don't know how good I could the write the title but it's a little bit complicated.
So I have this webpage in /music-maker endpoint which have a modal. In the modal there is an input field which takes in a user input and post it to the backend through AJAX post request. Then that user query is used to make an API request to https://example.com/api/?key=${key}&q=${query}. The result is then displayed in the webpage.
Now that part is working as it should be but the issue comes when I try to implement an infinite scrolling feature to it.
Please note at this point that the api request above returns the first page of data only and if I specify page 2 then it will return the data from page 2 of that exact query.
So whenever the user scrolls to the bottom I need to make another api request with that exact query as before but for page 2 which I am unable to accomplish. I've tried making a get AJAX request and used a global query variable to store the query from post request but it returns undefined.
Here are the endpoints of the app:
let query;
router.get('/music-maker', (req, res) => {
res.render('music-maker');
});
router.post('/music-maker', async (req, res) => {
query = encodeURI(req.body.input);
const key = '205XxXxX54825-0ab1';
try{
const url = `https://example.com/api/?key=${key}&q=${query}`;
const fullRes = await axios.get(url);
if( fullRes.status === 200 ) {
return res.json({
data: fullRes.data
});
}
}catch(err) {
res.json({
error: 'Unable to retrieve data.'
});
}
});
router.get('/music-maker/page', async (req, res) => {
console.log('1: ', query); // returns undefined
const pageQuery = req.query.q;
try{
console.log('2: ', pageQuery)
}catch(err) {
console.log(err)
}
});
Here are the AJAX requests:
const formInput = $(".searchbar input");
const userSearchInput = formInput.val();
const modalForm = $("form");
$(modalForm).submit((e) => {
e.preventDefault();
const actionUrl = $(e.target).attr("action");
$.ajax({
type: "POST",
url: actionUrl,
dataType: "json",
data: {
input: userSearchInput
},
beforeSend: function() {
$(formInput).val("");
},
success: function({ data }) {
if ( data ) {
$(".data-container").html(data);
} else if (data.error) {
$(".error-container").html(data.error);
}
},
complete: function() {
$(".loader-container").addClass("hidden");
},
});
});
// When the user scrolls to the bottom of the container, this ajax request fires
$('.data-container').on('scroll', function(e) {
const elem = $(e.currentTarget);
if (elem[0].scrollHeight - elem.scrollTop() == elem.outerHeight()) {
console.log(userSearchInput); // this is undefined
$.ajax({
type: "GET",
url: `/music-maker/page/`,
dataType: "json",
beforeSend: function() {
console.log('sending');
},
success: function( data ) {
console.log('incoming');
},
complete: function() {
console.log('complete');
},
});
}
});
How can I get the other pages' data of the same query by making an API request through AJAX?
update:
server part code
router.get("/music-maker/search/:query/:page", async (req, res) => {
let query = req.params.query;
let page = req.params.page;
console.log("query: " + query);
console.log("page: " + page);
return res.json({
query: req.params.query,
page: req.params.page
});
});
client/browser
let userSearchInput = "";
let pageNumber = 1;
function getMusicMaker() {
userSearchInput = $(".searchbar input").val();
userSearchInput = encodeURIComponent(userSearchInput);
const actionUrl = "/music-maker/search";
$.ajax({
url: `${actionUrl}/${userSearchInput}/${pageNumber}`,
dataType: "json",
beforeSend: function () {
$(".searchbar input").val("");
},
success: function (data) {
alert(data.query + "\n" + data.page)
}
});
}
$("form").submit((e) => {
e.preventDefault();
pageNumber = 1; // new search, reset page number
getMusicMaker();
});
$(".data-container").on("scroll", function (e) {
const elem = $(e.currentTarget);
if (elem[0].scrollHeight - elem.scrollTop() == elem.outerHeight()) {
pageNumber++; // set page 2,3,4,....
getMusicMaker();
}
});
I think you have multiple problems, to fix it need whole rewrite to your code (client and server) but I suggest to use single http method, POST or GET.
endpoint for static pages list:
/music-maker/1
/music-maker/2
or
/music-maker = /music-maker/page/1
/music-maker/page/2
for search
/music-maker/search/keywords
/music-maker/search/keywords/2
/music-maker/search/keywords/3
to set page number when user scroll you can do like this
let pageNumber = 1;
$('.data-container').on('scroll', function (e) {
const elem = $(e.currentTarget);
if (elem[0].scrollHeight - elem.scrollTop() == elem.outerHeight()) {
pageNumber++;
$.ajax({
type: "GET",
url: `/music-maker/page/${pageNumber}`,
.......
});
}
});
I have a function (requestLogin) that calls another function (post) which uses fetch to obtain some JSON from a server.
The post function work fine, but doesn't return the JSON object back to requestLogin. Any suggestions appreciated.
function post(path = "", json = "") {
let url = "/" + path;
return fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: json,
})
.then(response => response.json())
.then(json => {
console.log("*** RESULT=");
console.log(json);
return json;
});
}
function requestLogin(path, mobile, pwd) {
let data = {
"mobile": mobile,
"pwd": sha256(pwd)
}
let json = JSON.stringify(data);
post(path, json, (result2) => {
console.log("*** RESULT2=" + result2);
if (result2.result === 'ok') {
console.log("server json return valid result")
}
});
}
The fetch API returns a Promise, which is returned by your post function.
Instead of using a callback to handle the results, you should process the promise returned by the function.
For example:
post(path, json).then((result2) => {
console.log("*** RESULT2=" + result2);
if (result2.result === 'ok') {
console.log("server json return valid result")
}
});
this process is same as yours but you are using callback in wrong way in requestLogin function. you need to access that callBack method parameter in post function and pass json result in callBack method
function post(path = "", json = "", callBack) {
let url = "/" + path;
return fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: json,
})
.then(response => response.json())
.then(json => {
//passing json result in callBack method instead of returning
callBack(json);
});
}
function requestLogin(path, mobile, pwd) {
let data = {
"mobile": mobile,
"pwd": sha256(pwd)
}
let json = JSON.stringify(data);
post(path, json, (result2) => {
if (result2.result === 'ok') {
console.log("server json return valid result")
}
});
}
I would like to reentrant function in promise object.
this function contains Asynchronous processing.
however, this function dose NOT Work.
To be specified, DOES NOT fired ,next "then method".
the code is here
loopcount = 0;
getItemcount = 0;
global_ItemCol = [];
function GetItem_in_List_Over5000(parentSiteUrl, listGuid)
{
if (loopcount == 0) {
console.log("Enter FirstTime");
endPoint = parentSiteUrl + "/_api/Web/Lists(guid'" + listGuid + "')/Items?$top=3000&$select=Title,Id,ContentTypeId,HasUniqueRoleAssignments";
} else {
console.log("Eneter SecondTime");
}
return new Promise(function (resolve_GetItem_in_List5000, reject_GetItem_in_List5000) {
console.log("Eneter Inner Function");
$.ajax({
type: 'GET',
url: endPoint,
headers: { 'accept': 'application/json;odata=verbose', "X-RequestDigest": $("#__REQUESTDIGEST").val() },
success: function (data) {
console.log(data.d.__next);
if (data.d.__next) {
global_ItemCol = global_ItemCol.concat(data.d.results);
endPoint = data.d.__next;
loopcount++;
console.log("looopcount increment. " + global_ItemCol.length);
GetItem_in_List_Over5000(parentSiteUrl, listGuid);
} else {
global_ItemCol = global_ItemCol.concat(data.d.results);
var local_col = [];
local_col = local_col.concat(global_ItemCol);
loopcount = 0;
global_ItemCol.length = 0;
resolve_GetItem_in_List5000(local_col);
console.log("return call");
//return Promise.resolve().then(local_col);
resolve_GetItem_in_List5000(local_col);
}
},
error: function (error) {
OutputLog(error.responseJSON.error.message.value);
loopcount = 0;
reject_GetItem_in_List5000();
}
});
});
}
I called this function Added Array and Promise.All().
Thanks in advance.
You could try a recursive function. Store results in an array (not global but pass it to the recursive function). With every result set store the guid so you know what result set came from what guid (when requests start failing you know what you've done so far).
function GetItem_in_List_Over5000(parentSiteUrl, listGuid) {
const recur = (listGuid,results=[]) =>
$.ajax({
type: 'GET',
url: parentSiteUrl + "/_api/Web/Lists(guid'" + listGuid + "')/Items?$top=3000&$select=Title,Id,ContentTypeId,HasUniqueRoleAssignments",
headers: { 'accept': 'application/json;odata=verbose', "X-RequestDigest": $("#__REQUESTDIGEST").val() },
}).then(
function (data) {
console.log(data.d.__next);
if (data.d.__next) {
return recur(
data.d.__next,
results.concat([listGuid,data.d.results])
);
} else {
//add listGuid to result set so you know where it came from
return results.concat([listGuid,data.d.results]);
}
}
).fail(//newer jQuery can use .catch
err=>({type:"error",error:err,results:results})
);
return recur(listGuid)
}
GetItem_in_List_Over5000("url","guid")
.then(
results=>{
if((results&&results.type)===error){
console.log("something went wrong:",results.error);
console.log("have some results:",results.results);
}else{
console.log("got all results:",results);
}
}
)