How do I access the data from a json call/request - javascript

I'm making a request to questions.json, but I'm unsure how to capture the data returned by the response call. The JSON file is just an object but when I try to call response.names to get it, it's telling me response is not defined? Didn't I define it when I called the json function on it?
I'm thinking maybe because it's a promise, it's not technically defined? Unsure.
Here's my code:
fetchQuestions();
function createCategory(category, questions) {
const categoryDiv = document.createElement('div');
div.classList.add('category');
const h2 = document.createElement('h2');
h2.textContent = category;
categoryDiv.append(h2);
questions.forEach(question => {
const questionDiv = document.createElement('div');
questionDiv.classList.add('question');
const statusDiv = document.createElement('div');
statusDiv.classList.add(questions.status);
questionDiv.append(statusDiv);
const h3 = document.createElement('h3');
h3.textContent = question.name;
questionDiv.append(h3);
categoryDiv.append(questionDiv);
});
return categoryDiv;
}
function fetchQuestions() {
const myRequest = new Request('questions.json');
fetch(myRequest)
.then(response => response.json())
.then(getQuestionsByCategory(response.names))
.catch(console.error);
}
function getQuestionsByCategory(questions) {
const questionsByCategory = {};
questions.forEach(question => {
if (questionsByCategory.hasOwnProperty(question.category)) {
questionsByCategory[question.category].push(question);
} else {
questionsByCategory[question.category] = [question];
}
});
return questionsByCategory;
}

Related

Foreach for array

I have an array which I populate like so
var list = [];
featureLayer.queryFeatures(querySnTR)
.then((result) => {
result.attachmentInfos.forEach((x) => {
list.push(uriString + "/" + x.id);
});
});
console.log("list", list);
I print out the list with console.log and it returns values inside.
Afterwards I do a foreach to go through all the elements inside and create a div for each of them. The thing is, it doesn't even go in the foreach function.
list.forEach((x) => {
console.log("CL", list);
console.log("x element", x);
var image = document.createElement("img");
image.src = x;
image.className = "queryImg";
document.getElementById("queryResults").appendChild(image);
});
It doesn't print out CL or x element for that matter.
Any ideas as to why?
The whole original code, for reference
startup: function () {
var _that = this;
_this = _that;
this.map.on("click", function (e) {
_this.map.graphics.clear();
identifyTask = new IdentifyTask("https://server/arcgis/rest/services/MUNICIPALITY_BUNDLE/ZK_KATASTAR_NA_ZELENILO/MapServer");
identifyParams = new IdentifyParameters();
identifyParams.tolerance = 10;
identifyParams.returnGeometry = true;
identifyParams.layerIds = [1];
identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_ALL;
identifyParams.width = _this.map.width;
identifyParams.height = _this.map.height;
identifyParams.spatialReference = _this.map.spatialReference;
identifyParams.geometry = e.mapPoint;
identifyParams.mapExtent = _this.map.extent;
identifyTask.execute(identifyParams).then(function (data) {
objId = data[0].feature.attributes.objectid;
const querySnTR = {
where: "1 = 1",
outFields: ["*"]
};
var uriString = "https://server/arcgis/rest/services/MUNICIPALITY_BUNDLE/ZK_KATASTAR_NA_ZELENILO/MapServer/101/" + objId + "/attachments";
var featureLayer = new esri.layers.FeatureLayer(uriString);
featureLayer.queryFeatures(querySnTR)
.then((result) => {
result.attachmentInfos.forEach((x) => {
list.push(uriString + "/" + x.id);
});
});
const myFunction = async () => {
const { attachmentInfos } = await featureLayer.queryFeatures(querySnTR);
const list = attachmentInfos.map(({ id }) => `${uriString}/${id}`);
console.log("list", list);
list.forEach((x) => {
var image = document.createElement("img");
image.src = x;
image.className = "queryImg";
document.getElementById("queryResults").appendChild(image);
});
};
});
});
}
That's a trick on how the console works.
When you are executing the log the list is empty (100% sure) because you are populating it asynchronously. But the console has the reference to it and it will print it afterwards.
That's why your list is empty. You need to handle asynchrony here. You could work with an async/await approach or using promises, that will depend on the rest of your code, this is an example of how to do it with an async function (and rewritted it to modern javascript):
const myFunction = async () => {
const {attachmentInfos} = await featureLayer.queryFeatures(querySnTR);
const list = attachmentInfos.map(({id}) => `${uriString}/${id}`);
console.log("list", list);
list.forEach((x) => {
// put your code here
});
};
Edited:
Now that you share all your code you can simply do:
featureLayer.queryFeatures(querySnTR)
.then((result) => {
result.attachmentInfos.forEach((attachmentInfo) => {
var x = uriString + "/" + attachmentInfo.id
var image = document.createElement("img");
image.src = x;
image.className = "queryImg";
document.getElementById("queryResults").appendChild(image);
});
});
I would recommend you also to give vars meaningful names, not x but attachmentInfo, etc...

Node JS function that return https get request final edited data

Hello everybody I have a problem with the Node JS function that I want it to return https get request final edited data, I know there are a lot of solutions for this async problem but I tried them all and still can't figure out what is wrong with my code?
here is my function without any other solutions editing:
function getMovie(apiKey, gen) {
const baseUrl = "https://api.themoviedb.org/3/discover/movie?api_key=" + apiKey + "&language=en-US&include_adult=false&include_video=false&page=1&with_genres=" + gen;
https.get(baseUrl, function (responce) {
console.log(responce.statusCode);
var d = "";
responce.on("data", function (data) {
d += data;
});
responce.on("end", () => {
const finalData = [];
const moviesData = JSON.parse(d);
const result = moviesData.results;
const maxx = result.length;
const rand = Math.floor(Math.random() * maxx);
const title = result[rand].title;
const rDate = result[rand].release_date;
const overview = result[rand].overview;
const imageRoot = result[rand].poster_path;
const movieId = result[rand].id;
const movieRating = result[rand].vote_average;
// here will push those variables to finalData array
// then return it
return finalData;
});
}).on('error', (e) => {
console.error(e);
});
}
and want after this finalData returns:
const finalResult = getMovie(apiKey, genre);
it always returns undefined, How can I fix this? please anyone ca help me with this problem
thanks in advance.
I solved this problem using promises using this code:
const rp = require('request-promise');
function getMovie(url) {
// returns a promise
return rp(url).then(body => {
// make the count be the resolved value of the promise
let responseJSON = JSON.parse(body);
return responseJSON.results.count;
});
}
getMovie(someURL).then(result => {
// use the result in here
console.log(`Got result = ${result}`);
}).catch(err => {
console.log('Got error from getMovie ', err);
});

How to force post-processing to wait until all fetch processes finish in node.js?

I am collecting multiple data using fetch and then use them in multiple calculations.
var data_dict = []; // objects with ids
var fetch_data = function() {
let data_history = [];
data_dict.forEach(function (item, index) {
let id = item.id;
fetch(// with id)
.then(res => res.json())
.then(data=>{// fix data})
.then(fixed_data=> data_history.push(fixed_data))
.catch(err => console.log(err))
});
return data_history;
}
var use_fetched_data = function () {
let results = [];
// use data_history in calculating results
return results;
}
var use_fetched_data2 = function () {
let results = [];
// use data_history and obtained results in calculating another results
return results;
}
// get data_history2
var data_history2 = fetch_data();
// use data_history2 to find results1
var results1 = use_fetched_data ();
// use data_history2 and results1 to find results2
var results2 = use_fetched_data2 ();
I tried to use async & await to force waiting until all data are fetched, but results still get calculated before fetch is completed.
var force_wait = async function() {
// get data_history2
var data_history2 = await fetch_data();
// use data_history2 to find results1
var results1 = use_fetched_data ();
// use data_history2 and results1 to find results2
var results2 = use_fetched_data2 ();
}
force_wait();
How to do this properly?
thanks
The problem is that your fetch_data function doesn't wait for the requests:
const fetch_data = async function () {
const data_history = [];
requests = data_dict.map(({ id }, index) => {
return fetch('https://randomuser.me/api/')
.then(res => res.json())
.then(data => data.results[0])
.then(fixed_data => data_history.push(fixed_data))
});
try {
await Promise.all(requests)
} catch (err) {
console.error(err)
}
return data_history
}
After this change, your force_wait should work as expected.

TypeError: this is not a function

I have the following 2 files root/functions/util/constants.js and root/functions/handlers/images.js. The following are their source code
images.js
const path = require("path");
const os = require("os");
const sharp = require('sharp');
const fs = require('fs-extra');
const { uuid } = require("uuidv4");
const { Storage } = require('#google-cloud/storage');
const config = require("../util/config");
const gcs = new Storage({
projectId: config.projectId
});
const bucket = gcs.bucket(config.storageBucket);
const {
INVALID_TYPE_MESSAGE,
POST_SMALL_IMAGE_TYPE,
POST_MEDIUM_IMAGE_TYPE,
select_size_from_type
} = require("../util/constants");
const {
USER_PUBLIC_PROFILE_IMAGE
} = require("../util/schema")
const {error_response} = require("../util/validators");
exports.async_resize = async function(url, type) {
const size = select_size_from_type(type);//code beyond this are not executed
//some other code...
constants.js
const {error_response} = require("./validators");
const { admin } = require("./admin")
//Entity and collection names
//also contains fields of maps of schemas
const {
USER_PUBLIC_PROFILE_IMAGE
} = require("./schema");
const LIKES_COLLECTION = "likes";
const COMMENTS_COLLECTION = "comments";
const POSTS_COLLECTION = "posts";
const NOTIFICATIONS_COLLECTION = "notifications";
const FOLLOWERS = "followers";
const FOLLOWING = "following";
const PUBLIC_FOLLOWERS_SUBCOLLECTION = FOLLOWERS;
const PUBLIC_FOLLOWING_SUBCOLLECTION = FOLLOWING;
const USERS_PUBLIC_COLLECTION = "users_public";
const USERS_PRIVATE_COLLECTION = "users_private";
const PRIVATE_FOLLOWERS_SUBCOLLECTION = FOLLOWERS;
const PRIVATE_FOLLOWING_SUBCOLLECTION = FOLLOWING;
const LIKE_TYPE = "like";
const COMMENT_TYPE = "comment";
const POST_TYPE = "post";
const NOTIFICATION_TYPE = "notification"
const POST_SMALL_IMAGE_TYPE = "small";
const POST_MEDIUM_IMAGE_TYPE = "medium";
const POST_MAXIMUM_ORIGINAL_TYPE = "original";
const SERVER_TIME = admin.firestore.FieldValue.serverTimestamp();
const INVALID_TYPE_MESSAGE = "Invalid recipient type";
const select_collection_from_type = (type) => {
if (type === LIKE_TYPE) {
return LIKES_COLLECTION;
} else if (type === POST_TYPE) {
return POSTS_COLLECTION;
} else if (type === COMMENT_TYPE) {
return COMMENTS_COLLECTION;
} else {
return error_response("Data type is not within scope of project");
}
}
//can be used for profile_image also
const select_size_from_type = function (type) {
if (type === POST_SMALL_IMAGE_TYPE) {
return 64;
} else if (type === POST_MEDIUM_IMAGE_TYPE) {
return 128;
} else if (type === POST_MAXIMUM_ORIGINAL_TYPE) {
return 256;
} else if (type === USER_PUBLIC_PROFILE_IMAGE) {
return 1; //same as before, need a better number for this
//
} else {
return error_response("Data type is not within scope of project");
}
}
module.exports = {
LIKE_TYPE,
LIKES_COLLECTION,
COMMENT_TYPE,
COMMENTS_COLLECTION,
PUBLIC_FOLLOWERS_SUBCOLLECTION,
PUBLIC_FOLLOWING_SUBCOLLECTION,
PRIVATE_FOLLOWERS_SUBCOLLECTION,
PRIVATE_FOLLOWING_SUBCOLLECTION,
USERS_PUBLIC_COLLECTION,
USERS_PRIVATE_COLLECTION,
POST_TYPE,
POSTS_COLLECTION,
INVALID_TYPE_MESSAGE,
SERVER_TIME,
NOTIFICATIONS_COLLECTION,
POST_SMALL_IMAGE_TYPE,
POST_MEDIUM_IMAGE_TYPE,
POST_MAXIMUM_ORIGINAL_TYPE,
select_collection_from_type,
select_size_from_type
};
I tried running a script and it keeps telling me that
TypeError: select_size_from_type is not a function
at exports.async_resize (/Users/Isaac/root/functions/handlers/images.js:36:16)
but I really dont see any syntax error. I'm using Webstorm and the functions can be navigated. Can someone enlighten me what else can be the cause of the syntax error?
Update
I also tried console.log(select_size_from_type); in images.js, console.log(select_size_from_type); before it was exported in constants.js. It prints undefined and [Function: select_size_from_type] respectively. Even when I tried changing the signature of async_resize as well as select_size_from_type, all of them gave the same error as well. Any other function which does not involve select_size_from_type works perfectly.
Functions can be defined in two ways
Way 1
function my_function_name (arguments) {
...function body
}
Way 2
const my_function_name = function (arguments) {
... function body
}
In your case, it seems like you are trying to mix both the ways.
Try changing your function definition to
exports.async_resize = async(url, type) => {
...function body
}
try this
const size = this.select_size_from_type(type);//code beyond this are not executed
or export your file like this
module.exports.select_size_from_type=select_size_from_type
or
module.exports={size_type : select_size_from_type}
and then require it like this
const getsizefromtype=require(....)
select_size_from_type= getsizefromtype.size_type

Pagination in Zapier

I am trying following code to get all records from a paginated API in Zapier.
const limitPerPage = 20;
const apiUrl = "https://myurl.com/data";
var lastCursor = null;
var output = null;
const getContent = async function (cursor) {
let actualUrl = apiUrl + `?cursor=${cursor}&limit=${limitPerPage}`;
var apiResults = await fetch(actualUrl)
.then(resp => {
return resp.json;
});
}
const getEntireContentList = async function (cursor) {
const results = await getContent(cursor);
console.log("Retreiving data from API for cursor : " + cursor);
if (results.metadata.cursor !== "") {
return results.concat(await getEntireContentList(results.metadata.cursor));
} else {
return results;
}
};
(async() => {
const entireList = await getEntireContentList();
console.log(entireList);
output = entireList;
callback(null, entireList);
})();
I get error as
You did not define output! Try output = {id: 1, hello: await Promise.resolve("world")};
How can I fix this?
Your problem is that though you're awaiting in that function, the top-level carries on and execution ends before your code has had a chance to run.
The good news is, Zapier wraps your code in an async function already, so you can use await at the top level (per these docs).
Try this instead:
const limitPerPage = 20;
const apiUrl = "https://myurl.com/data";
let lastCursor = null;
// var output = null; // zapier does this for you already
const getContent = async function (cursor) {
const actualUrl = apiUrl + `?cursor=${cursor}&limit=${limitPerPage}`;
const rawResponse = await fetch(actualUrl)
return resp.json() // async function, you had it as a property
}
const getEntireContentList = async function (cursor) {
const results = await getContent(cursor);
console.log("Retreiving data from API for cursor : " + cursor);
if (results.metadata.cursor !== "") {
return results.concat(await getEntireUserList(results.metadata.cursor)); // should this be named getEntireContentList?
} else {
return results;
}
};
return {
results: await getEntireContentList()
}
I noticed this is a recursive approach. That's fine, but remember that you've got limited execution time. You also might hit memory limits (depending on how many objects you're returning), so keep an eye on that.

Categories

Resources