i am working on a simple app that will fetch data from an Api and display it.
a have this function
const getAUserProfile = () => {
const api = 'https://randomuser.me/api/';
// make API call here
return fetch(api)
.then(response => response.json())
.then(response => displayUserPhotoAndName(response))
notify(`requesting profile data ...`);
};
this is where i try to fetch the data and pass as a parameter to the displayUserPhotoAndName function.
Now in the displayUserPhotoAndName function i try to create a statement that de-structures the data parameter and obtains the results property from it;
i tried to Create a second statement in the next line that de-structures the results variable i just created, and obtain the first item from it (it is an Array! See https://randomuser.me/api/). the de-structured array item should be declared as profile. This represents the profile data for the user gotten from the API call that i want to display in my app.
this is the displayUserPhotoAndName function
const displayUserPhotoAndName = (data) => {
if(!data) return;
// add your code here
const {results} = data;
const {profile} = results;
document.getElementById('name').innerHTML = profile[results];
clearNotice();
};
now i am trying to display the title, first name and last name with this line of code document.getElementById('name').innerHTML = profile[0].title + profile[0].first + profile[0].last;.
this is not working when i try to run it in sapio
There is no profile property in data or in the results array. So your assignment const {profile} = results; will be undefined
You could point profile at the first item in the results array. Then use the property paths for what you want to display
const displayUserPhotoAndName = (data) => {
if (!data) return;
// add your code here
const {results} = data;
const profile = results[0];
const fullName = profile.name.first + ' ' + profile.name.last;
document.getElementById('name').innerHTML = fullName
};
const getAUserProfile = () => {
const api = 'https://randomuser.me/api/';
// make API call here
return fetch(api)
.then(response => response.json())
.then(displayUserPhotoAndName)
};
getAUserProfile()
<div id="name"></div>
You need this probably:
document.getElementById('name').innerHTML = results[0].name.title + results[0].name.first + results[0].name.last;
Because the json looks like this:
{
"results":[
{
"gender":"male",
"name":{
"title":"mr",
"first":"vidar",
"last":"sjursen"
},
"location":{
"street":"bestum tverrvei 7385",
"city":"bratsberg",
"state":"sogn og fjordane",
"postcode":"8514",
"coordinates":{
"latitude":"57.7278",
"longitude":"-95.6342"
},
"timezone":{
"offset":"+7:00",
"description":"Bangkok, Hanoi, Jakarta"
}
},
"email":"vidar.sjursen#example.com",
"login":{
"uuid":"fbc411b4-f34c-497f-acff-8294ddcf8738",
"username":"whitezebra569",
"password":"shoes",
"salt":"8prWID0j",
"md5":"02ea3e887aaa140ad312905801ae2353",
"sha1":"c9a66349e68825dc02c74618aac8572fbdd01e5b",
"sha256":"8297cc85be1127223761fb80b8f554632a6a37c35d58d435293a8f6b2dca19f3"
},
"dob":{
"date":"1952-10-19T01:20:59Z",
"age":66
},
"registered":{
"date":"2011-11-12T03:06:29Z",
"age":7
},
"phone":"88795425",
"cell":"92914506",
"id":{
"name":"FN",
"value":"19105218888"
},
"picture":{
"large":"https://randomuser.me/api/portraits/men/25.jpg",
"medium":"https://randomuser.me/api/portraits/med/men/25.jpg",
"thumbnail":"https://randomuser.me/api/portraits/thumb/men/25.jpg"
},
"nat":"NO"
}
],
"info":{
"seed":"48917bf154395ac4",
"results":1,
"page":1,
"version":"1.2"
}
}
Which means, when you do this:
const {results} = data;
Then the array will be there, and the array doesn't have profile property to get it with:
const {profile} = results;
The problem is with this line of code
const {results} = data;
--> const {profile} = results;
the "{results}" will take the results property out of your response which in turn is an array.
when you try to take {profile} from results there is no such property like profile in it.
Which makes the profile variable undefined. This was the problem.
Note: The {something} variable will look for property in your object. [this case the property is something]
Hope this one helps
this is what worked for me
const displayUserPhotoAndName = (data) => {
if(!data) return;
// add your code here
const {results} = data;
const [profile] = [...results];
const fullName = profile.name.title + ' ' + profile.name.last + ' ' + profile.name.first;
document.getElementById('name').innerHTML = fullName
document.getElementById('photo').src = profile.picture.large
displayExtraUserInfo(profile);
clearNotice();
};
const {profile} = results; here profile is undefined because results is an array with no property profile.
You need to do const profile = [...results]; and then document.getElementById('name').innerHTML = profile[0].name.title + profile[0].name.first + profile[0].name.last;
fetch('https://randomuser.me/api/')
.then(res => res.json())
.then(data => {
if (!data) return;
const {
results
} = data;
const profile = [...results];
console.log(profile)
document.getElementById('name').innerHTML = profile[0].name.title + profile[0].name.first + profile[0].name.last;
}
)
<div id="name"></div>
Related
So I'm trying to implement a search bar in my Flask application that will list out the cities that are being inputted by the user and exist in the JSON API results of a weather API.
I am following a tutorial and basically have the same code as ths: https://codepen.io/jamesqquick/pen/XWJxBQv
However, in my implementation, the .filter() and .map() functions don't work, I get the following error:
TypeError for map() and filter()
How do I fix this?
Here's my code (the regular generateHTML in the first part of the code with fetching current weather data already works, only the "SEARCH BAR" section has problems):
let currentType = "current.json";
let userCity = "London";
const apiData = {
url: "http://api.weatherapi.com/v1",
type: `${currentType}`,
key: "40cd513af8aa446484a92837213011",
city: `${userCity}`,
};
const { url, type, key, city } = apiData;
const apiUrl = `${url}/${type}?key=${key}&q=${city}`;
console.log("apiUrl:");
console.log(apiUrl);
fetch(apiUrl)
.then((data) => {
if (data.ok) {
return data.json();
}
throw new Error("Response not ok.");
})
.then((locationRequest) => generateHtml(locationRequest))
.catch((error) => console.error("Error:", error));
const generateHtml = (data) => {
console.log("data:")
console.log(data);
console.log("data.location.name:")
console.log(`${data.location.name}`);
const html = `
<div class="weather-location">
<h1>${data.location.name}, ${data.location.country}</h1></div>
<div class="details">
<span>Tmp: ${data.current.temp_c} °C</span>
<span>Feels like: ${data.current.feelslike_c} °C</span>
</div>
`;
const weatherDiv = document.querySelector(".weather");
weatherDiv.innerHTML = html;
};
/* SEARCH BAR */
const citiesList = document.getElementById('weather-cities');
const searchBar = document.getElementById('weather-searchbar');
let cities = [];
console.log("citiesList:");
console.log(citiesList);
console.log("searchBar:");
console.log(searchBar);
searchBar.addEventListener('keyup', (e) => {
userCity = e.target.value.toLowerCase();
console.log("usercity:");
console.log(userCity);
const filteredCities = cities.filter((city) => {
return (
city.name.toLowerCase().includes(userCity) ||
city.region.toLowerCase().includes(userCity) ||
city.country.toLowerCase().includes(userCity)
);
});
displayCities(filteredCities);
});
const loadCities = async () => {
try {
currentType = "search.json";
const res = await fetch(apiUrl);
cities = await res.json();
console.log("cities:");
console.log(cities);
displayCities(cities);
} catch (err) {
console.error(err);
}
};
const displayCities = (cities) => {
let htmlString = cities
.map((city) => {
return `
<li class="character">
<h2>${city.location.name}</h2>
<p>Temperature: ${city.current.temp_c} °C</p>
<p>Feels like:${city.current.feelslike_c} °C></p>
</li>
`;
})
.join('');
citiesList.innerHTML = htmlString;
};
loadCities();
<div class="other-stats">
<div class="weather-search">
<input type="text" id="weather-searchbar" placeholder="Your city"></input>
<ul id="weather-cities"></ul>
</div>
<div class="weather"></div>
</div>
<script src="../static/weather_api.js"></script>
Array.prototype.filter() and Array.prototype.map() are used for arrays, the cities property is getting a javascript object. You need to assign an array to "cities".
Ok, it seems I solved the issue for now. In displayCities, for the HTML section I put city.location.name like I'd do to get the name in "current.json" API call, but in the new API call "search.json" I get an array of dictionaries that contain different information directly, not with different categories like "location" or "current". So city.name is enough. To clarify better, see console.log entries:
API call "current.json"
API call "search.json"
const displayCities = (cities) => {
let htmlString = cities
.map((city) => {
return `
<li class="character">
<p>${city.name}</p>
</li>
`;
})
.join('');
citiesList.innerHTML = htmlString;
};
The getURL() function creates an array of scraped URLs from the original URL. getSubURL() then loops through that array and scrapes all of those pages' URLs. Currently, this code outputs just fine to the console, but I don't know how to wait for my data to resolve so I can push all gathered data to a single array. Currently, when I try and return sites and then push to array, it only pushes the last value. I believe it's a promise.all(map) situation, but I don't know how to write one correctly without getting an error. Ideally, my completed scrape could be called in another function. Please take a look if you can
const cheerio = require('cheerio');
const axios = require('axios');
let URL = 'https://toscrape.com';
const getURLS = async () => {
try {
const res = await axios.get(URL);
const data = res.data;
const $ = cheerio.load(data);
const urlQueue = [];
$("a[href^='http']").each((i, elem) => {
const link = $(elem).attr('href');
if (urlQueue.indexOf(link) === -1) {
urlQueue.push(link);
}
});
return urlQueue;
} catch (err) {
console.log(`Error fetching and parsing data: `, err);
}
};
const getSubURLs = async () => {
let urls = await getURLS();
try {
//loop through each url in array
for (const url of urls) {
//fetch all html from the current url
const res = await axios.get(url);
const data = res.data;
const $ = cheerio.load(data);
//create object and push that url into that object
let sites = {};
sites.url = url;
let links = [];
//scrape all links and save in links array
$("a[href^='/']").each((i, elem) => {
const link = $(elem).attr('href');
if (links.indexOf(link) === -1) {
links.push(link);
}
//save scraped data in object
sites.links = links;
});
// returns list of {url:'url', links:[link1,link2,link3]}
console.log(sites);
}
} catch (err) {
console.log(`Error fetching and parsing data: `, err);
}
};
Don't think this is a Promise related issue at heart.
You'll need to collect your sites into an array that is initialized outside the loop. Then when getSubURLs() resolves, it will resolve to your array:
const getSubURLs = async() => {
let urls = await getURLS();
let siteList = [];
try {
for (const url of urls) {
// :
// :
// :
siteList.push(sites);
}
} catch (err) {
console.log(`Error fetching and parsing data: `, err);
}
return siteList; // array of objects
};
getSubURLs().then(console.log);
I have fetched some data from firebase like so:
getUserData = () => {
database
.ref('orders/')
.once('value')
.then(function(snapshot) {
const exists = snapshot.val() !== null;
if (exists) {
let data = snapshot.val();
console.log("DATA IS: ", data);
}
});
}
The image shows the console log. I am trying to render everything on a table in react. I'm having trouble iterating through the data. Do I need to convert it into an array first?
I am looking to render everything from the item_id, displayName, email, all order info
First You need to convert into array and then you can use map for retrieve data.
For example:
if data is in array form then you can mapping of objects.
I hope it will helps you.
data.map((detail)=>{
console.log(detail.email);
})
You can get data from function,
function getUserData = () => {
database
.ref('orders/')
.once('value')
.then(function(snapshot) {
const exists = snapshot.val() !== null;
if (exists) {
let data = snapshot.val();
//console.log("DATA IS: ", data);
return data;
}
});
}
var data = getUserData();
data.forEach(function(item){
console.log(data.email);
console.log(data.img);
console.log(data.name);
console.log(data.section);
} )
New javascript provide Object.values().SO, you convert your data into array like below and use it.
getUserData = () => {
database
.ref('orders/')
.once('value')
.then(function(snapshot) {
const exists = snapshot.val() !== null;
if (exists) {
let data = snapshot.val();
console.log("DATA IS: ", data);
//use Object.values(data)
const dataArray = Object.values(data);
//now you can map your dataArray
}
});
}
I'm trying to grab some data(title, last name, first name and also large photo of the user profile returned by the API.) from the API https://randomuser.me/api/, which seem to not be working.
const displayUserPhotoAndName = (data) => {
if(!data) return;
// add your code here
let {results} = data;
let [profile] = results;
document.querySelector('h2').textContent = profile.name.title +' '+ profile.name.last +' '+ profile.name.first;
document.querySelector('img').src = profile.picture.large;
displayExtraUserInfo(profile);
clearNotice();
};
const getAUserProfile = () => {
const api = 'https://randomuser.me/api/';
// make API call here
fetch(api)
.then((resp) => resp.json())
.then(data => {displayUserPhotoAndName()});
notify(`requesting profile data ...`);
};
const displayBirthdate = ({dob = 'dob'}) => {
document.querySelector('.details').textContent = dob.age;
}
const displayPhone = ({phone = 'phone', cell = 'cell'}) => {
document.querySelector('.details').textContent = phone + ', ' + cell;
}
const displayAddress = ({location = 'location'}) => {
document.querySelector('.details').textContent = location.street + ', ' + location.city + ', ' + location.state;
}
You are passing the data to the function.Do like below
const getAUserProfile = () => {
const api = 'https://randomuser.me/api/';
// make API call here
fetch(api)
.then((resp) => resp.json())
.then(data => {displayUserPhotoAndName(data)}); //this line is changed
notify(`requesting profile data ...`);
};
Here is the line that will get all the required properties
let {results:[{ name: { title , first , last } , picture:{ large } }]} = data;
Here is how you can do it and also handle bad data with default values. Also, do not forget to pass data to your function in the then callback:
const display = data => {
const { results: [{ name: { title, first, last } = {}, picture: { large } = {} }] = [] } = data || {};
console.log(title, first, last, large);
};
fetch('https://randomuser.me/api/').then(r => display(r.json()));
I'm working on a Bus Stop google assistant script in node.js
I based it on the weather API example by Google. Given the right API key, the weather function will work and return the weather for a place on a date.
The Bus Stop API will return the correct output in the console.log, but the output does not get passed on to the else if statement where the function is called.
I get 2 errors:
"Unhandled rejection" Which can be alleviated by commenting out the reject code in the callBusApi.
"TypeError: Cannot read property 'json' of undefined
at callBusApi.then.catch (/user_code/index.js:45:9)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)" This is where it breaks. I think because it doesn't get the output from the function.
My script looks as follows:
'use strict';
const http = require('http');
const host = 'api.worldweatheronline.com';
const wwoApiKey = 'enter a working key';
exports.weatherWebhook = (req, res, re) => {
if(req.body.queryResult.intent['displayName'] == 'weather'){
// Get the city and date from the request
let city = req.body.queryResult.parameters['geo-city']; // city is a required param
// Get the date for the weather forecast (if present)
let date = '';
if (req.body.queryResult.parameters['date']) {
date = req.body.queryResult.parameters['date'];
console.log('Date: ' + date);
}
// Call the weather API
callWeatherApi(city, date).then((output) => {
res.json({ 'fulfillmentText': output }); // Return the results of the weather API to Dialogflow
}).catch(() => {
res.json({ 'fulfillmentText': `I don't know the weather but I hope it's good!` });
});
}
else if (req.body.queryResult.intent['displayName'] == 'mytestintent'){
callBusApi().then((output) => {
re.json({ 'fulfillmentText': output }); // Return the results of the bus stop API to Dialogflow
}).catch(() => {
re.json({ 'fulfillmentText': `I do not know when the bus goes.` });
});
}
};
function callBusApi () {
return new Promise((resolve, reject) => {
http.get({host: 'v0.ovapi.nl', path: '/stopareacode/beunav/departures/'}, (re) => {
let boy = '';
re.on('data', (d) => {boy+=d});
re.on('end',() => {
let response = JSON.parse(boy)
var firstKey = Object.keys(response['beunav']['61120250']['Passes'])[0];
var timeKey = Object.keys(response['beunav']['61120250']['Passes'][firstKey])[19];
var destKey = Object.keys(response['beunav']['61120250']['Passes'][firstKey])[1];
let destination = response['beunav']['61120250']['Passes'][firstKey][destKey];
let datetime = response['beunav']['61120250']['Passes'][firstKey][timeKey];
let fields = datetime.split('T');
let time = fields[1];
let output = `Next bus to ${destination} departs at ${time} .`;
console.log(output)
resolve(output);
});
re.on('error', (error) => {
console.log(`Error talking to the busstop: ${error}`)
reject();
});
});
});
};
function callWeatherApi (city, date) {
return new Promise((resolve, reject) => {
let path = '/premium/v1/weather.ashx?format=json&num_of_days=1' +
'&q=' + encodeURIComponent(city) + '&key=' + wwoApiKey + '&date=' + date;
console.log('API Request: ' + host + path);
http.get({host: host, path: path}, (res) => {
let body = '';
res.on('data', (d) => { body += d; });
res.on('end', () => {
let response = JSON.parse(body);
let forecast = response['data']['weather'][0];
let location = response['data']['request'][0];
let conditions = response['data']['current_condition'][0];
let currentConditions = conditions['weatherDesc'][0]['value'];
let output = `Current conditions in the ${location['type']}
${location['query']} are ${currentConditions} with a projected high of
${forecast['maxtempC']}°C or ${forecast['maxtempF']}°F and a low of
${forecast['mintempC']}°C or ${forecast['mintempF']}°F on
${forecast['date']}.`;
console.log(output);
resolve(output);
});
res.on('error', (error) => {
console.log(`Error calling the weather API: ${error}`)
reject();
});
});
});
}
It appears that your method has a parameter too much
exports.weatherWebhook = (req, res, re) => {
should be:
exports.weatherWebhook = (req, res) => {
And as well on the variable 're' used in the handling of the 'mytestintent' inside the webhook.
This explains the 'not defined' error when trying to set a json value on it.
Regarding your 2 question: It usually comes when the value of the variable is not defined.
First check wheather you have defined the JSON variable in your .js file.
Or its in some other format.