I am iterating over a JSON object via fetch().
I would like to access one of the objects within the objects and iterated over it accessing the key: value pairs and output the values to HTML via list items.
When I try to output the values I only get the last value of the powerstats (there are 6)
What do I need to change here to have all values display properly on my page?
I tried to create a for loop and iterate over the value.length, however value.length gives me 2 as an answer.
Feel free to use the provided api key.
function get_hero(rand_number) {
const api_key = '10156555926000957';
let hero_id = rand_number;
let hero_url = `https://www.superheroapi.com/api/${api_key}/${hero_id}`;
fetch(hero_url)
.then(res => {
return res.json();
})
.then( data => {
let ps = data.powerstats;
Object.entries(ps).forEach(([key, value]) => {
console.log(key + ' - ' + value) // key - value
console.log(value.length)
const smt = `<ul>
<li>${value}</li>
<li>${value}</li>
<li>${value}</li>
<li>${value}</li>
<li>${value}</li>
<li>${value}</li>
</ul>`;
const power_stats = document.getElementById('powerstats');
power_stats.innerHTML = smt;
})
})
.catch(function() {
console.log('error')
})
}
Sry didn't had coffee yet, XD
so your problem is that you replace all of the power_stats.innerHTML = smt; with smt over and over again. You want to use element.appendChild(element) to ADD to a list. Not overwrite
.then(data => {
const ps = data.powerstats;
const power_stats = document.getElementById('powerstats');
const list = document.createElement(`ul`)
power_stats.appendChild(list)
Object.entries(ps).forEach(([key, value]) => {
console.log(key + ' - ' + value) // key - value
console.log(value.length)
const smt = document.createElement(`li`)
smt.innerText = `The heroes ${key} is ${value}`
list.appendChild(smt)
})
})
Currently you function return void, so you don't wait for fetch, so you should return promise:
function get_hero(rand_number) {
const api_key = '10156555926000957';
let hero_id = rand_number;
let hero_url = `https://www.superheroapi.com/api/${api_key}/${hero_id}`;
return fetch(hero_url)
.then(res => {
return res.json();
})
.then( data => {
let ps = data.powerstats;
Object.entries(ps).forEach(([key, value]) => {
console.log(key + ' - ' + value) // key - value
console.log(value.length)
const smt = `<ul>
<li>${value}</li>
</ul>`;
const power_stats = document.getElementById('powerstats');
power_stats.innerHTML = smt;
})
})
.catch(function() {
console.log('error')
})
}
Using:
get_hero(123).then(() => console.log('done!'));
(for me https://www.superheroapi.com/ is not responding, so maybe it is not the only problem)
Related
I'm trying to set some values based in a conditional so I've decided to make a map in parent array to change some values, but the right values aren't returning for parent array.
app.get('/api/painel/mapa-processos/:idplanejamento/:rotina', (req, res) => {
let idLista = req.params.idplanejamento
let rotina = req.params.rotina
schemas.schemaOps.find({IDPLANEJAMENTO: idLista}).select('NUMEROOP')
.exec(async (err, result) => {
let listOps = result.map((result)=>{return result.NUMEROOP})
const connection = await oracleDB.connect()
let lastLancamentos = (await connection.execute(queriesOracle.lastLancamentos(listOps))).rows
lastLancamentos.map(async (row) => {
let lastAptoMobile = (await connection.execute(queriesOracle.lastAptoMobile(row[0]))).rows
if (lastAptoMobile.length > 0){
if (row[2] < lastAptoMobile[0][1]) {
row[1] = lastAptoMobile[0][0]
row[2] = lastAptoMobile[0][1]
row[3] = lastAptoMobile[0][3]
row[4] = null
row[5] = lastAptoMobile[0][2]
row[8] = lastAptoMobile[0][4]
console.log(row)
}}
return row
})
connection.close()
res.json(lastLancamentos)
})
})
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);
});
I am trying to make axios POST requests inside a for loop. However, the axios post POST request is being run n times with only the last value of the loop. Running twice with value sheetName="Virudhunagar Beds". Below is my piece of code:
const axios = require('axios')
const sheetDistrictMap = {
"Ariyalur Beds": "5ea0abd3d43ec2250a483a4f", "Virudhunagar Beds": "5ea0abd3d43ec2250a483a58"
}
let promises = [];
for (sheetName in sheetDistrictMap) {
promises.push(
axios.post('https://tncovidbeds.tnega.org/api/hospitals', {
District: sheetDistrictMap[sheetName],
FacilityTypes: ["CHO", "CHC", "CCC"],
IsGovernmentHospital: true,
IsPrivateHospital: true,
pageLimit: 100
})
.then(res => {
var outputJsonArray = [];
for (i = 0; i < res.data.result.length; i++) {
var rowJson = {};
var rowdata = res.data.result[i];
rowJson["Name"] = rowdata["Name"];
outputJsonArray.push(rowJson);
}
console.log("Parsed sheet: " + sheetName);
console.log(outputJsonArray);
console.log("========================================================");
})
.catch(error => {
console.error(error)
})
)
}
Promise.all(promises).then(() => console.log("All data scraped"));
How do I make async calls with each loop parameter?
You are hit the closure inside loops issue. You can use let and const keywords to declare the sheetName variable. Each iteration through the loop will have a new variable sheetName with loop scope.
for (let sheetName in sheetDistrictMap) {
// the rest code
}
For more info, see JavaScript closure inside loops – simple practical example
Try adding const to the sheetName variable. The problem is that your variable without it behaves like var that is global in most cases. Adding a const makes the variable block-scoped so that every iteration will have a unique variable instead of using the last value that was assigned to the sheetName.
for (const sheetName of Object.keys(sheetDistrictMap)) {
promises.push(
axios.post('https://tncovidbeds.tnega.org/api/hospitals', {
District: sheetDistrictMap[sheetName],
FacilityTypes: ["CHO", "CHC", "CCC"],
IsGovernmentHospital: true,
IsPrivateHospital: true,
pageLimit: 100
})
.then(res => {
var outputJsonArray = [];
for (i = 0; i < res.data.result.length; i++) {
var rowJson = {};
var rowdata = res.data.result[i];
rowJson["Name"] = rowdata["Name"];
outputJsonArray.push(rowJson);
}
console.log("Parsed sheet: " + sheetName);
console.log(outputJsonArray);
console.log("========================================================");
})
.catch(error => {
console.error(error)
})
)
}
I think there are two things here :
let or const in the for loop which creates a global scope for the variable
How you are getting data from the promises. You don't need to .then after pushing it to the array instead do this:
const axios = require('axios')
const sheetDistrictMap = {
"Ariyalur Beds": "5ea0abd3d43ec2250a483a4f", "Virudhunagar Beds": "5ea0abd3d43ec2250a483a58"
}
let promises = [];
for (let sheetName in sheetDistrictMap) {
promises.push(
axios.post('https://tncovidbeds.tnega.org/api/hospitals', {
District: sheetDistrictMap[sheetName],
FacilityTypes: ["CHO", "CHC", "CCC"],
IsGovernmentHospital: true,
IsPrivateHospital: true,
pageLimit: 100
})
)
}
Promise.all(promises).then((data) =>
//data will array and in same sequence you hit the api
// do the below processing for every response
var outputJsonArray = [];
for (i = 0; i < res.data.result.length; i++) {
var rowJson = {};
var rowdata = res.data.result[i];
rowJson["Name"] = rowdata["Name"];
outputJsonArray.push(rowJson);
}
//console.log("Parsed sheet: " + sheetName); // make sure you get the sheetName
console.log(outputJsonArray);
console.log("========================================================");
})
.catch(error => {
console.error(error)
})
I am using the custom function option for downloading a CSV usingMaterialTable. In the function I am modifying the data of only three columns.
When exportCsv is executed then the data array will contain the last changes which will results on a wrong output.
const downloadCsv = (data, fileName) => {
const finalFileName = `${fileName}.csv`;
const a = document.createElement("a");
a.href = URL.createObjectURL(new Blob([data], { type: "text/csv" }));
a.setAttribute("download", finalFileName);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
export default function ReTable(props) {
const resultsData = useSelector((state) => state.results.data);
return (
<div>
<MaterialTable
columns={columns}
data={resultsData}
options={{
........
.......
.....
exportCsv: (columns, data) => {
const csvData = [...resultsData];
csvData.forEach(item => {
item.account = '="' + item.account + '"';
item.zip4 = '="' + item.zip4 + '"';
item.zip5 = '="' + item.zip5 + '"';
});
const dataRows = csvData.map(({ tableData, ...row }) => Object.values(row));
const csvContent = [header, ...dataRows].map(e => e.join(',')).join("\n");
downloadCsv(csvContent, props.name);
},
I don’t want to change the data so I have created a new csvData but apparently its it is effecting the data.
I am not sure what I am doing wrong ? I need to update the columns only ones.
Thank you
You're just doing a shallow copy of the array when you call [...resultsData]. Either use a library that will do a deep copy, find one of the many SO answers that will provide a solution, or do the work of converting values when you call map instead of worrying about making the array immutable:
exportCsv: (columns, data) => {
const colsToTransform = ['account', 'zip4', 'zip5'];
const dataRows = resultsData.map(x => Object.entries(x)
.map(kvp => (colsToTransform.includes(kvp[0])) ? '="' + kvp[1] + '"' : kvp[1]));
const csvContent = [header, ...dataRows].map(e => e.join(',')).join("\n");
downloadCsv(csvContent, props.name);
}
I am trying to return an array of pushed data from promise, then loop multiple times to populate all data. For instance, I got a list of brands and a function to take in brand parameter and return an array of pushed data.
var datasetarr = [];
brandlist = ['Bh', 'Ruffles'];
let promiseKey = new Promise((resolve, reject) => {
for(var i = 0; i < brandlist.length; i++){
datasetarr = populateData(brandlist[i], datasetarr);
}
resolve(datasetarr);
});
promiseKey.then((arr) => {
console.log('complete promise');
for(var i = 0; i < arr.length; i++){
console.log(arr[i].date + ' ' + arr[i].total);
}
});
The error message is
Uncaught (in promise) TypeError: Cannot read property 'length' of undefined
at promiseKey.then
My data fetching has no problem as I managed to print out the details. This means that the promise is not resolve properly. Is that the correct way to return an array from promise? I not sure which part was wrong.
Firstly, your populateData needs to return a Promise - in this case, it would be the resolved array of promises created in data.forEach
var brandlist = ['Bh', 'Ruffles'];
let promiseKey = Promise.all(brandlist.map(brand => populateData(brand)))
.then(results => [].concat(...results)); // flatten the array of arrays
promiseKey.then((arr) => {
console.log('complete promise');
for(var i = 0; i < arr.length; i++){
console.log(arr[i].date + ' ' + arr[i].total);
}
});
function populateData(brand, datasetarr) {
console.log('go in');
var query;// = // query by brand parameter
return query.once('value').then(data => {
var promises = [];
data.forEach(snapshot => {
// get each receipt item details
// get receipt details by receipt ID
var query;// = // query receipts
promises.push(query.once('value').then(data => {
// removed code
// managed to print out here so data fetching is not a problem
console.log(brand + ' ' + date + ' ' + itemTotal);
return {date: date, total: itemTotal};
}));
});
return Promise.all(promises);
});
}
Or, using the snapshotToArray function I gave you in this answer a week ago
const snapshotToArray = snapshot => {
const ret = [];
snapshot.forEach(childSnapshot => {
ret.push(childSnapshot);
});
return ret;
};
function populateData(brand, datasetarr) {
console.log('go in');
var query;// = // query by brand parameter
return query.once('value').then(data => Promise.all(snapshotToArray(data).map(snapshot => {
// get each receipt item details
// get receipt details by receipt ID
var query;// = // query receipts
return query.once('value').then(data => {
// removed code
// managed to print out here so data fetching is not a problem
console.log(brand + ' ' + date + ' ' + itemTotal);
return {date: date, total: itemTotal};
});
})));
}
While it's possible to work with a global datasetarray variable to which you push from anywhere, I would recommend against it. Instead, write a method getData that returns (a promise for) an array, and after calling that multiple times (once for every brand) you concatenate them together.
const brandlist = ['Bh', 'Ruffles'];
const promiseKey = Promise.all(brandlist.map(getData)).then(arrays => [].concat(...arrays));
promiseKey.then(arr => {
console.log('complete promise');
for (const item of arr)
console.log(item.date + ' ' + item.total);
});
function getData(brand) { // no array parameter!
console.log('go in');
const query = …; // query by brand parameter
return query.once('value').then(data => {
const promises = toArray(data).map(snapshot => {
const query = …; // get receipt item details by receipt ID
return query.once('value').then(data => {
…
return {date: date, total: itemTotal}; // don't push, just return the result
});
return Promise.all(promises); // resolves with an array of results
}); // resolves with that same result array
}
function toArray(forEachable) {
const arr = [];
forEachable.forEach(x => { arr.push(x); });
return arr;
}