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
Related
I am a new learning JS. Who can help me complete this code. I have 2 problem:
render child Node user Chat when click without duplicate
how to remove child Node user when close chat window
full code is here: Jsfiddle
// event handling when click
handleEvents: function () {
let _this = this;
userChatList.onclick = function (e) {
const userNode = e.target.closest(".user-chat__item");
if (userNode) {
userIndex = Number(userNode.getAttribute("user-num"));
_this.renderUserChat(userIndex);
const getChatWithItems = document.querySelectorAll(".chat-with__item");
getChatWithItems.forEach(item => {
item.onclick = function(e){
const itemNode = e.target.closest(".chat-with__top i");
if(itemNode){
chatWithList.removeChild(chatWithItem);
}
}
})
}
}
},
//render user chat with someone
renderUserChat: function (num) {
// console.log(userIndex);
chatWithItem = document.createElement("li");
chatWithItem.classList.add("chat-with__item");
chatWithItem.setAttribute('user-num', num);
chatWithItem.innerHTML = `
<div class="chat-with__top">
<div class="chat-with__img">
<img src="${this.users[num].img}" alt="${this.users[num].name}">
<span class="user__status ${this.users[num].status}"></span>
</div>
<p class="chat-with__name">${this.users[num].name}</p>
<i class="fa-solid fa-xmark"></i>
</div>
<div class="chat-with__body">
<ul class="chat__text">
<li class="chat-text__user">Hey. 👋</li>
<li class="chat-text__user user__chatting">I am here</li>
<li class="chat-text__user user__chatting">What's going on?</li>
<li class="chat-text__user">Have you finished the "project 2" yet?</li>
<li class="chat-text__user user__chatting">I have been fixed bugs</li>
<li class="chat-text__user">OK.</li>
</ul>
</div>
<div class="chat-width__footer">
<i class="fa-solid fa-image"></i>
<i class="fa-solid fa-folder"></i>
<div class="chat-width__input">
<input type="text" id="send-sms" name="send SMS" placeholder="...">
</div>
<i class="fa-solid fa-paper-plane-top"></i>
</div>
`
chatWithList.appendChild(chatWithItem);
},
<ul class="chat-with__list">
</ul>
I have not still known how to solve it, up to now
Just keep track which chat windows are opened in an object.
To give you basic idea of the concept:
// storage for opened chat windows
// this variable must be accessible by event handlers
const openedChats = {};
In chat opened event handler:
if (openedChats[userId]) //check if chat already opened
return;
const chatWithItem = document.createElement("li");
...
openedChats[userId] = chatWithItem; //store window
chatWithList.appendChild(chatWithItem); //show window
In chat close event handler:
const chatWithItem = openedChats[userId]; // get opened chat
if (chatWithItem)
{
chatWithItem.parentNode.removeChild(chatWithItem); // destroy window
delete openedChats[userId]; // remove window
}
If you need to get list of all userIds that have opened chat windows, use:
const openedChatsIds = Object.keys(openedChats);
Finnaly I find the way to code. This is my way
handleEvents: function () {
let _this = this;
let currentChat = [];
userChatList.onclick = function (e) {
const userNode = e.target.closest(".user-chat__item");
if (userNode) {
userIndex = Number(userNode.getAttribute("user-num"));
// get value 'userIndex' for currentChat array
function getCurrentChat(arr, index) {
arr.push(index);
}
// check value userIndex in a currentChat array
function checkCurrentChat(arr, index) {
if (arr.indexOf(index) < 0) {
getCurrentChat(currentChat, userIndex);
return true;
} else {
return false;
}
}
let isExisted = checkCurrentChat(currentChat, userIndex);
// console.log(isExisted);
if (isExisted) {
_this.renderUserChat(userIndex);
}
const getChatWithItems = chatWithList.querySelectorAll(".chat-with__item");
getChatWithItems.forEach( function(item) {
item.onclick = function (e) {
const closeChat = e.target.closest(".chat-with__top i");
if(closeChat){
const getNum = Number(closeChat.parentElement.getAttribute("user-num"));
chatWithList.removeChild(item);
const findNum = currentChat.indexOf(getNum);
currentChat.splice(findNum, 1);
}
}
})
}
}
}
inside, i add an attribute to get number (userIndex):
<div class="chat-with__top" user-num ="${num}">
if you use second .parentElement, it will ok.
closeChat.parentElement.parentElement.getAttribute("user-num")
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
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);
}
This relates to my previous question.
I have created the following script, which takes information from an API and displays it on a webpage using template literals. Everything works fine, expect in Opera Mini, where the data from the API does not load.
<script language="JavaScript">
window.onload = function(){
//// UI templates
var app = document.getElementById('root')
var container = document.createElement('div')
container.setAttribute('class', 'container')
app.appendChild(container)
cardHeight = window.innerHeight
const API = 'https://api.the-odds-api.com/v3/odds/?sport=soccer_epl®ion=uk&apiKey=KEY'
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
let data = JSON.parse(xhr.responseText)
console.log(data, 'data')
data.data.forEach((match, index) => {
console.log(match, 'match')
const card = document.createElement('div')
card.setAttribute('class', 'card')
const odds = match.sites[0].odds
// styles
const cssClasses = {
team: 'flex flex-row',
radio: 'mla',
title: 'f4'
}
const markup = `
<div class='mb3 flex flex-column bg-near-white' style="height: ${cardHeight}px">
<div class="${cssClasses.team}">
<h2 class="${cssClasses.title}">${match.teams[0]}</h2>
<span class="${cssClasses.radio}">${odds.h2h[0]}<input type="radio" name="${index}" value="1"></span>
</div>
<div class="${cssClasses.team}">
<h2 class="${cssClasses.title}">Draw</h2>
<span class="${cssClasses.radio}">${odds.h2h[1]}<input type="radio" name="${index}" value="1"></span>
</div>
<div class="${cssClasses.team}">
<h2 class="${cssClasses.title}">${match.teams[1]}</h2>
<span class="${cssClasses.radio}">${odds.h2h[2]}<input type="radio" name="${index}" value="1"></span>
</div>
</div>
`;
card.innerHTML = markup
console.log(card, 'card')
container.appendChild(card)
})
}
if (xhr.status == 404) {
console.log("not working")
}
}
}
xhr.open('get', API, true);
xhr.send();
}
</script>
Is there something I am doing wrong?
I am using the odds API
I have a simple site that is getting a list of books from the Google Books API.
I have a separate file called scripts.js that is getting all the book information (title, author, ISBN, link to the image).
I want to create a div for each book in a gallery style page, where there is a picture of the book and on top of the book is the Title, Author, and ISBN.
I've tried creating the DIV's in Javascript but I want there to be an h3, p, and img inside of each DIV and I can't seem to wrap my head around how I could do that in Javascript.
My HTML code for the gallery:
<div id="content">
<h2>My Bookshelf</h2>
<div class="book">
<!-- The book image is the background of the div -->
<h3 class="book-title">Title</h3>
<p class="book-isbn">ISBN: 000000</p>
<p class="book-author">Authors: ABC</p>
</div>
</div>
My Javascript code that cycles through the JSON file and returns the needed information.
// Returns an array with the book title, ISBN, author, bookmark icon, description, image
apiRequest.onreadystatechange = () => {
if (apiRequest.readyState === 4) {
const response = JSON.parse(apiRequest.response);
var bookList = response.items;
// Removes old search results before display new ones
bookSection.innerHTML = "";
for (let i = 0; i < bookList.length; i++) {
console.log(i);
var title = (bookList[i]["volumeInfo"]["title"]);
try {
var isbn = (bookList[i]["volumeInfo"]["industryIdentifiers"][0]["identifier"]);
} catch (TypeError) {
var isbn = "ISBN Not Available";
}
var author = (bookList[i]["volumeInfo"]["authors"]);
var description = (bookList[i]["description"]);
try {
var image = (bookList[i]["volumeInfo"]["imageLinks"]["thumbnail"]);
} catch (TypeError) {
var image = "img/unavailable.png";
}
}
}
}
You can use template literals to make your job easier.
You can do it like this:
var bookSection = `<div id="content">
<h2>My Bookshelf</h2>
<div class="book">
<!-- The book image is the background of the div -->
<h3 class="book-title">${titleVar}</h3>
<p class="book-isbn">ISBN: ${ISBNVar}</p>
<p class="book-author">Authors: ${AuthorsVar}</p>
</div>
</div>`;
Learn more about template literals from here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
Your code should look something like this
apiRequest.onreadystatechange = () => {
if (apiRequest.readyState === 4) {
const response = JSON.parse(apiRequest.response);
var bookList = response.items;
// Removes old search results before display new ones
bookSection.innerHTML = "";
let bookListHtmlMarkup = '';
for (let i = 0; i < bookList.length; i++) {
console.log(i);
// Declaring book object
const book = {};
const bookListHtmlMarkup = '';
book['title'] = (bookList[i]["volumeInfo"]["title"]);
try {
book['isbn'] = (bookList[i]["volumeInfo"]["industryIdentifiers"][0]["identifier"]);
} catch (TypeError) {
book['isbn'] = "ISBN Not Available";
}
book['author'] = (bookList[i]["volumeInfo"]["authors"]);
book['description'] = (bookList[i]["description"]);
try {
book['image'] = (bookList[i]["volumeInfo"]["imageLinks"]["thumbnail"]);
} catch (TypeError) {
book['image'] = "img/unavailable.png";
}
bookListHtmlMarkup += `
<div class="book">
<div class="book-image">
<img src="${book.image}" alt="Image unavailable" />
</div>
<div class="book-info">
<h3 class="book-title">${book.title}</h3>
<p class="book-isbn">ISBN: ${book.isbn}</p>
<p class="book-author">Author: ${book.author}</p>
<p class="book-description">Author: ${book.description}</p>
</div>
</div>
`;
}
// Assigning generated markup to innerHTML of bookSection
bookSection.innerHTML = bookListHtmlMarkup;
}
}