Format date and text data from API - javascript

I am working with Github API and I am displaying the data from users. When the date is displayed I want it to only have the date user.created_at with DD/MM/YY and not the whole hour. Also when the user has no Biography user.bio the data appears as null, and I want it to display the text 'The user has no bio'. I have not figured out the way to do both things so if you could help me I would very much appreciate it
Here below the code:
const APIURL = 'https://api.github.com/users/'
const main = document.getElementById('main')
const form = document.getElementById('form')
const search = document.getElementById('search')
async function getUser(username){
try{
const { data } = await axios(APIURL + username)
createUserCard(data)
getRepos(username)
}catch (err){
if(err.response.status == 404){
createErrorCard('No profile with this Username')
}
}
}
async function getRepos(username){
try{
const { data } = await axios(APIURL + username + '/repos?sort=created')
addReposToCard(data)
}catch (err){
createErrorCard('Problem Fetching Repos')
}
}
function createUserCard(user){
const cardHTML = `
<div class="card">
<div>
<img src="${user.avatar_url}" alt="${user.name}" class="avatar">
</div>
<div class="user-info">
<div class="header">
<h2>${user.name}</h2>
<p class="date">Joined ${user.created_at}</p>
</div>
<p>#${user.login}</p>
<p>${user.bio}</p>
<ul>
<div class="list">
<li>${user.followers} </li>
<li>${user.following} </li>
<li>${user.public_repos} </li>
</div>
<div class="list-names">
<strong>Followers</strong>
<strong>Following</strong>
<strong>Repos</strong>
</div>
</ul>
<div class="additional-data">
<p class="location"><img src="./img/location.svg" alt="Location" class="img" /> ${user.location} </p>
<img src="./img/link.svg" alt="Link" class="img" />${user.html_url}
</div>
<div id="repos"></div>
</div>
</div>`
main.innerHTML = cardHTML
}
function createErrorCard(msg){
const cardHTML = `
<div class="card">
<h1>${msg}</h1>
</div>
`
main.innerHTML = cardHTML
}
function addReposToCard(repos){
const reposEl = document.getElementById('repos')
repos
.slice(0, 5)
.forEach(repo => {
const repoEl = document.createElement('a')
repoEl.classList.add('repo')
repoEl.href = repo.html_url
repoEl.target = '_black'
repoEl.innerText = repo.name
reposEl.appendChild(repoEl)
})
}
form.addEventListener('submit', (e) => {
e.preventDefault()
const user = search.value
if(user){
getUser(user)
search.value = ''
}
})

in the case of user.bio you can use the ternary operator:
(conditional)?value when conditional true: value when conditional false
for example:
${(user.bio!="null")?user.bio:"The user has no bio"}
or
${(user.bio!=null)?user.bio:"The user has no bio"}
in the case of date github helps us giving us a formated string that we can cast to a date using new Date() and format it using Date.prototype.toLocaleString()
${(new Date(user.created_at)).toLocaleDateString()}
in this case is not needed to pass parameters to toLocaleDateString() but I encourage you to read about this function here

Related

HTML not responding with JavaScript filter

This is an update to a previous question I had. I am making a simple page that filters the first 9 Pokemon by their type after clicking a button. I will include the code below. I ran the code through a validator and there were no issues. Also, I don't see any errors in the console. I did console the type and the array every time a button is clicked so it looks like the filter is working. But, nothing is happening on the page.
Here's a link to the page: https://sobreratas.github.io/pokemonfilter/
const pokemon=[{name:"Bulbasaur",image:"images/bulbasaur.png",number:1,type:"Grass"},{name:"Ivysaur",image:"images/ivysaur.png",number:2,type:"Grass"},{name:"Venusaur",image:"images/venusaur.png",number:3,type:"Grass"},{name:"Charmander",image:"images/charmander.png",number:4,type:"Fire"},{name:"Charmeleon",image:"images/charmeleon.png",number:5,type:"Fire"},{name:"Charizard",image:"images/charizard.png",number:6,type:"Fire"},{name:"Squirtle",image:"images/squirtle.png",number:7,type:"Water"},{name:"Wartortle",image:"images/wartortle.png",number:8,type:"Water"},{name:"Blastoise",image:"images/blastoise.png",number:9,type:"Water"}];
const sectionCenter = document.querySelector('.section-center');
const btnContainer = document.querySelector('.btn_container');
window.addEventListener('DOMContentLoaded', function() {
displayPokemonMenu();
displayMenuButtons();
})
function displayPokemonMenu(array) {
let pokemonMap = pokemon.map(function(item) {
return `<div class="pokemon-item">
<img class="photo" src="${item.image}" alt="${item.name}">
<h2>${item.name}</h2>
<h3># <span id="number">${item.number}</span></h3>
<h4>Type: <span id="type">${item.type}</span></h4>
</div>`
})
pokemonMap = pokemonMap.join('');
sectionCenter.innerHTML = pokemonMap;
}
function displayMenuButtons() {
let types = pokemon.reduce(function(values, item) {
if (!values.includes(item.type)) {
values.push(item.type);
}
return values
}, ['All']);
const typesBtns = types.map(function(type) {
return `<button class="filter-btn" data-id="${type}">${type}</button>`
}).join('');
btnContainer.innerHTML = typesBtns;
const filterBtns = btnContainer.querySelectorAll('.filter-btn');
filterBtns.forEach(function(btn) {
btn.addEventListener('click', function(e) {
let type = e.currentTarget.dataset.id;
console.log(type)
const pokemonFilter = pokemon.filter(function(item) {
if (type === item.type) {
return item;
}
})
if (type === 'All') {
displayPokemonMenu(pokemon);
} else {
displayPokemonMenu(pokemonFilter);
console.log(pokemonFilter);
}
})
})
}
<img class="logo" src="images/logo.png" alt="logo">
<br>
<br>
<div class="btn_container">
<button class="filter-btn" data-id="All">All</button>
</div>
<div class="section-center">
<div class="pokemon-item">
<img class="photo" src="images/bulbasaur.png" alt="Bulbasaur">
<h2>Bulbasaur</h2>
<h3># <span id="number">1</span></h3>
<h4>Type: <span id="type">Grass</span></h4>
</div>
</div>

Can't get the images from an API to show up

I'm using an API to get information for a database sort of thing. I want the images to be displayed to the right of the text but the images aren't showing up at all. I tried multiple different keys and still nothing. Here is what it currently looks like:
The images are not showing up as you can see.
Here is the JS (its pulling the data from here https://api.tvmaze.com/shows/347/episodes):
// DATABASE const sunnyList = document.getElementById('sunnyList'); let sunnyInfo = [];
searchBar.addEventListener('keyup', (e) => { const searchTarget = e.target.value.toLowerCase(); const filteredSunny = sunnyInfo.filter(sunny => {
return sunny.name.toLowerCase().includes(searchTarget) || sunny.airdate.toLowerCase().includes(searchTarget) || sunny.airtime.includes(searchTarget) });
displayInfo(filteredSunny); });
const loadLayout = async () => {
try {
const res = await fetch('https://api.tvmaze.com/shows/347/episodes');
sunnyInfo = await res.json();
displayInfo(sunnyInfo);
} catch (err) {
console.error(err);
} };
const displayInfo = (sunny) => {
const htmlString = sunny
.map((sunny) => {
return `
<li class="character">
<div class="detail">
<h2>${sunny.name}</h2>
<p>Season ${sunny.season} Episode ${sunny.number}</p>
<p>${sunny.airdate}</p>
<p>${sunny.airtime}</p>
<p>${sunny.rating.average}</p>
</div>
<img src="${sunny.image}"></img>
</li>
`;
})
.join('');
sunnyList.innerHTML = htmlString; };
loadLayout();
I've tried sunny.image.medium and sunny.image.original but it still doesn't show up.
Any help is appreciated :)
The image is not a url string, but an object with the following shape:
{
medium: string,
original: string
}
where both strings contain the actual image URLs.
For your use case medium probably makes more sense, so you can do this:
<img src="${sunny.image?.medium}"></img>
Edit
Added optional chaining because some items do not have image property.
The problem your are facing is that not all objects have images.
Please try this code:
const displayInfo = (sunny) => {
const htmlString = sunny
.map((sunny) => {
const img = sunny.image ? sunny.image.medium : "https://picsum.photos/200/300"
return `
<li class="character">
<div class="detail">
<h2>${sunny.name}</h2>
<p>Season ${sunny.season} Episode ${sunny.number}</p>
<p>${sunny.airdate}</p>
<p>${sunny.airtime}</p>
<p>${sunny.rating.average}</p>
</div>
<img src=${img} />
</li>
`;
})
.join('');
sunnyList.innerHTML = htmlString; };

Can someone please help me refactor this code? I am return HTML via JS and my function is way too long. Maybe i can make function to return HTML?

I was looking to shorten up this code if possible. I am making a TV show search app and the API I am using has some empty arrays in it. I was wondering if I can set some default parameters? I've been stuck on this for days! I know it's going to be an eye sore to read, but any help is much appreciated. Thank you for looking at my code.
const imgContainer = document.querySelector('.img-container')
const clearBtn = document.querySelector('.clear-btn')
searchForm.addEventListener('submit', function (e) {
e.preventDefault()
fetchApi()
})
const fetchApi = async () => {
const userInput = searchForm.elements.query.value
const config = { params: { q: userInput } }
const fetch = await axios.get('https://api.tvmaze.com/search/shows', config)
showDetails(fetch.data)
}
const showDetails = (request) => {
const reqMap = request.map(function (shows) {
const showImg = shows.show.image
const showTitle = shows.show.name
const showDesc = shows.show.summary
const showGenres = shows.show.genres[0]
if (showImg && showTitle && showDesc && showGenres) {
let showImgMed = shows.show.image.medium
return `<div class="show-details">
<h1>${showTitle}</h1>
<img class="stock-img" src="${showImgMed}" alt="">
<p class="show-desc">Description: ${showDesc}</p>
<p class="show-genre">Genre: ${showGenres}</p>
</div>`
} else if (!showGenres && !showImg && !showDesc) {
return `<div class="show-details">
<h1>${showTitle}</h1>
<img class="stock-img" src="https://www.westernheights.k12.ok.us/wp-content/uploads/2020/01/No-Photo-Available.jpg" alt="">
<p class="show-desc">Description: N/A</p>
<p class="show-genre">Genre: N/A</p>
</div>`
} else if (!showImg) {
return `<div class="show-details">
<h1>${showTitle}</h1>
<img class="stock-img" src="https://www.westernheights.k12.ok.us/wp-content/uploads/2020/01/No-Photo-Available.jpg" alt="">
<p class="show-desc">Description: ${showDesc}</p>
<p class="show-genre">Genre: ${showGenres}</p>
</div>`
} else if (!showDesc) {
let showImgMed = shows.show.image.medium
return `<div class="show-details">
<h1>${showTitle}</h1>
<img class="stock-img" src="${showImgMed}" alt="">
<p class="show-desc">Description: N/A</p>
<p class="show-genre">Genre: ${showGenres}</p>
</div>`
} else if (!showGenres) {
let showImgMed = shows.show.image.medium
return `<div class="show-details">
<h1>${showTitle}</h1>
<img class="stock-img" src="${showImgMed}" alt="">
<p class="show-desc">Description: ${showDesc}</p>
<p class="show-genre">Genre: N/A</p>
</div>`
}
}).join('')
imgContainer.innerHTML = reqMap
}
Define the varying values up front, then write out the HTML string once and interpolate. Change the mapper function to:
const {
image,
name,
summary = 'N/A',
genres,
} = shows.show;
const imageSrc = image ? image.medium : 'https://www.westernheights.k12.ok.us/wp-content/uploads/2020/01/No-Photo-Available.jpg';
const showGenres = genres[0] || 'N/A';
return `
<div class="show-details">
<h1>${name}</h1>
<img class="stock-img" src="${imageSrc}" alt="">
<p class="show-desc">Description: ${summary}</p>
<p class="show-genre">Genre: ${showGenres}</p>
</div>
`;
You can just normally render HTML and then change elements parameters via javascript.
var element = document.createElement('div');
element.innerHTML = `<div class="show-details">
<h1>aa</h1>
<img class="stock-img" src="aa" alt="">
<p class="show-desc">Description: aa</p>
<p class="show-genre">Genre: aa</p>
</div>`.trim();
Let's say your variable showGenres == false
if(!showGenres) {
element.querySelector("p.show-desc").textContent = "Genre: N/A"
}
You can have content defined once in element variable and then change it dynamically :)
https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute

Already known weather for city should not repeat again

I'm trying my first weather api APP. Here I'm trying to achive that if the city weather is already displayed , It should give the message "You already know the weather" . and should not repeat the weather
Here is my code. Anyone Please look at my code ...
What is the mistake I have been made.
<div class="main">
<div class="container">
<div class="search_por">
<h2>Weather </h2>
<div class="validate_msg color_white"></div>
<form>
<label for=""></label>
<input type="search" class="input_text" value="">
<button type="submit" id="sub_button" class="srh_button">Search</button>
</form>
<!-- <canvas id="icon1" width="150" height="75"></canvas> -->
<div class="dat_weather">
<ul id="list_it">
</ul>
</div>
</div>
</div>
</div>
var get_text=document.querySelector("form");
get_text.addEventListener("submit",e=>{
e.preventDefault();
var input_val=document.querySelector('input').value;
const apiKey="bc4c7e7826d2178054ee88fe00737da0";
const url=`https://api.openweathermap.org/data/2.5/weather?q=${input_val}&appid=${apiKey}&units=metric`;
fetch(url,{method:'GET'})
.then(response=>response.json())
.then(data=>{console.log(data)
const{main,sys,weather,wind}=data;
//icons-end
var error_ms=document.getElementsByClassName("validate_msg")[0];
var iconcode = weather[0].icon;
console.log(iconcode);
var li=document.createElement("Li");
var weatherinfo=`<div class="nameci font_40" data-name="${data.name},${sys.country}"><span>${data.name}</span><sup>${sys.country}</sup></div>
<div class="temp_ic">
<img class="weat_icon" src="http://openweathermap.org/img/w/${iconcode}.png">
<div class="deg">${Math.floor( main.temp )}<sup>o</sup></div>
</div>
<div class="clear">
<div>${weather[0].description}</div>
</div>
`;
li.innerHTML=weatherinfo;
var ulid=document.getElementById("list_it");
ulid.appendChild(li);
var city_name=data.name;
console.log(skycons);
var listitems=document.querySelectorAll('#list_it');
const listArray=Array.from(listitems);
if(listArray.length>0)
{
var filtered_array=listArray.filter(el=>{
let content="";
if(input_val.includes(','))
{
if(input_val.split(',')[1].length>2)
{
alert("hving 2 commos");
inputval=input_val.split(',')[0];
content=el.querySelector(".nameci span").textContent.toLowerCase();
//content=el.querySelector(".nameci").innerHTML.toLowerCase();
//content=inputval.toLowerCase();
}
else
{
content=el.querySelector(".nameci").dataset.name.toLowerCase();
}
alert(filtered_array);
}
else
{
content=el.querySelector(".nameci span").textContent.toLowerCase();
}
console.log(inputval.toLowerCase());
return inputval.toLowerCase();
});
if(filtered_array.length>0)
{
console.log(filtered_array.length);
error_ms.innerHTML="You Already know the weather of this country....";
get_text.reset();
return;
}
}
})
.catch((error)=>{
error_ms.innerHTML="Please Enter a valid city Name";
});
var error_ms=document.getElementsByClassName("validate_msg")[0];
error_ms.innerHTML="";
//var get_text=document.querySelector("form");
get_text.reset();
});
My full code is here:
https://codepen.io/pavisaran/pen/wvJaqBg
Let's try keeping track of a list of displayed locations outside of the callback:
var get_text = document.querySelector("form");
// Keep Track Of Displayed Cities Here Instead
let displayed = [];
get_text.addEventListener("submit", e => {
e.preventDefault();
var input_val = document.querySelector('input').value;
const apiKey = "bc4c7e7826d2178054ee88fe00737da0";
const url = `https://api.openweathermap.org/data/2.5/weather?q=${input_val}&appid=${apiKey}&units=metric`;
fetch(url, {method: 'GET'})
.then(response => response.json())
.then(data => {
var error_ms = document.getElementsByClassName("validate_msg")[0];
const {main, sys, weather, wind, name} = data;
if (displayed.length > 0) {
// Filter Displayed Based on Current vs name from data (response)
const filtered_array = displayed.filter(el => el === name);
if (filtered_array.length > 0) {
error_ms.innerHTML = "You Already know the weather of this country....";
get_text.reset();
return Promise.resolve();
}
}
// Add City To Array of Displayed Cities
displayed.push(name);
// Do Rest of Code to Add New City
var iconcode = weather[0].icon;
var li = document.createElement("Li");
var weatherinfo = `<div class="nameci font_40" data-name="${data.name},${sys.country}"><span>${data.name}</span><sup>${sys.country}</sup></div>
<div class="temp_ic">
<img class="weat_icon" src="http://openweathermap.org/img/w/${iconcode}.png">
<div class="deg">${Math.floor(main.temp)}<sup>o</sup></div>
</div>
<div class="clear">
<div>${weather[0].description}</div>
</div>
`;
li.innerHTML = weatherinfo;
var ulid = document.getElementById("list_it");
ulid.appendChild(li);
})
.catch((error) => {
error_ms.innerHTML = "Please Enter a valid city Name";
});
var error_ms = document.getElementsByClassName("validate_msg")[0];
error_ms.innerHTML = "";
get_text.reset();
});
You have to just check for the value which is coming from api whether it's present on your list or not. you can try this.
li.innerHTML=weatherinfo;
var ulid=document.getElementById("list_it");
var isPresent = false;
var items = ulid.getElementsByTagName("li");
for (var i = 0; i < items.length; i++){
if(items[i].innerHTML == li.innerHTML){
alert("you already know the weather")
isPresent = true;
}
}
if(!isPresent){
ulid.appendChild(li);
}

Why am I not getting a status code of 200?

I am using the github api to display the user info and repos on a webpage.
<body>
<section id='input'>
<h1>Github Repository Obtainer</h1>
<input type="text", id="input-text", placeholder="Enter a Github username">
<button id="submit-button">Search</button>
</section>
<hr>
<section id="main">
<ul id="tag">
<li class="tag-item">User Info</li>
<li class="tag-item">User Repository</li>
</ul>
<hr>
<section id="user">
</section>
<section id="repo">
<ul id="repository-list">
</ul></section>
</section>
<script src="index.js"></script>
</body>
</html>
button = document.getElementById("submit-button");
button.addEventListener("click", () => {
const user = document.getElementById("input-text").value;
const xmr = new XMLHttpRequest();
xmr.open("GET", `https://api.github.com/users/${user}/repos`, true);
xmr.onload = () => {
let list = document.getElementById("repository-list")
if(this.status === 200){
console.log(this.status)
const data = JSON.parse(this.responseText);
var output = '';
data.forEach((item, index) => {
let tempChild = document.createElement("li")
tempChild.setAttribute("id", "list-item")
output += `<ul>
<li><span>Name:</span> ${item.name}</li>
<li><span>Description:</span> ${item.description}</li>
<li><span>URL:</span> ${item.html_url}</li>
</ul>`
tempChild.innerHTML = output
list.appendChild(tempChild)
})
} else {
list.innerHTML = "<h1>User cannot be found</h1>"
}
}
xmr.send();
const xmr2 = new XMLHttpRequest();
xmr2.open("GET", `https://api.github.com/users/${user}`, true);
xmr2.onload =() => {
if(this.status === 200){
const data2 = JSON.parse(this.responseText);
var output = '';
output += `<h1>${data2.login}</h1>
<img src="${data2.avatar_url}">
<ul id="user-info-list">
<li><span>Bio: </span>${data2.bio}</li>
<li><span>Public Repositories: </span>${data2.public_repos}</li>
<li><span>Public Gists: </span>${data2.public_gists}</li>
<li><span>Followers: </span>${data2.followers}</li>
<li><span>Following: </span>${data2.following}</li>
<li><span>Location: </span>${data2.location}</li>
<li><span>Created on: </span>${data2.created_at.slice(0, 10)}</li>
<li><span>URL: </span>${data2.html_url}</li>
<ul>`
} else{
var output = "<h1>User does not exist</h1>"
}
document.getElementById("user").innerHTML = output
}
xmr2.send()
tabChecker();
})
tabChecker() is another function in the js file, which I have not included here. It is not causing the problem.
The output is always user not found even though the user exists on github.
Please provide answers to what the problem might be.
Also when I console.log(this.status) the output in console is blank.
The links for the api works fine when I put the link in the browser
You should use xmr2.status instead of this.status OR don't use arrow function: xmr2.onload = function() {...}. Arrow functions don't have its own this.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Categories