Fetch API Not displaying Images properly - TV Show Website - javascript

I'm a beginner when it comes to coding and the biggest issue I have is to understand WHY something doesn't work (how to diagnose an error). I tried to combine what I learned from Colt Steele on Udemy with fetch API and so far, I've managed to make it work to list the NAMES of the movies when you search, but when I try to display the IMAGES, they seem to not work and it seems like it's trying to load them from my PC rather than from the TVMaze API. Here's my code:
function searchShow(query) {
const url = `https://api.tvmaze.com/search/shows?q=${query}`;
fetch(url)
.then(response => response.json())
.then((jsonData) => {
const resultsNames = jsonData.map(element => element.show.name);
const resultsImages = jsonData.map(e => e.show.image);
console.log(resultsNames);
renderResults(resultsNames);
console.log(resultsImages);
renderImages(resultsImages);
document.getElementById("errorMessage").innerHTML = "";
})
.catch((error) => {
document.getElementById("errorMessage").innerHTML = error;
})
}
function renderResults(resultsNames) {
const list = document.getElementById("resultsList");
list.innerHTML = "";
resultsNames.forEach(result => {
const element = document.createElement("li");
element.innerText = result;
list.appendChild(element);
});
}
function renderImages(resultsImages) {
const list2 = document.getElementById("imagesDisplay");
list2.innerHTML = "";
resultsImages.forEach(result => {
const imgShow = document.createElement("IMG");
imgShow.src = result;
list2.appendChild(imgShow);
})
}
let searchTimeoutToken = 0;
window.onload = () => {
const searchFieldElement = document.getElementById("searchField")
searchFieldElement.onkeyup = (event) => {
clearTimeout(searchTimeoutToken);
searchTimeoutToken = setTimeout(() => {
searchShow(searchFieldElement.value);
}, 250);
};
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TV Show</title>
</head>
<body>
<h1>TV Search</h1>
<input type="text" id="searchField" placeholder="Search a TV Show...">
<ul id="resultsList"></ul>
<ul id="imagesDisplay"></ul>
<div id=" errorMessage">
</div>
<script src="script.js"></script>
</body>
</html>
Can you please help me understand why is this not working and also, how can I make it display in a list like this:
-Name of the show
-Image of the show
-2nd name of the 2nd show
-2nd image of the 2nd show
etc.
Thank you in advance!

If you look at your images, you will see the src as [object Object] instead of the url to your image. You need to access the property of your object, in this case there's a few to choose from that represent different sized images.
I've modified your snippet to get what you want.
function searchShow(query) {
const url = `https://api.tvmaze.com/search/shows?q=${query}`;
fetch(url)
.then(response => response.json())
.then((jsonData) => {
let shows = jsonData.map(element => element.show);
renderShows(shows);
document.getElementById("errorMessage").innerHTML = "";
})
.catch((error) => {
document.getElementById("errorMessage").innerHTML = error;
})
}
function renderShows(shows) {
const list = document.getElementById("resultsList");
list.innerHTML = "";
shows.forEach(show => {
const element = document.createElement("li");
const img = document.createElement("img");
const text = document.createElement("span");
img.src = show.image.original;
text.innerText = show.name;
element.appendChild(text);
element.appendChild(img);
list.appendChild(element);
});
}
let searchTimeoutToken = 0;
window.onload = () => {
const searchFieldElement = document.getElementById("searchField")
searchFieldElement.onkeyup = (event) => {
clearTimeout(searchTimeoutToken);
searchTimeoutToken = setTimeout(() => {
searchShow(searchFieldElement.value);
}, 250);
};
}
img {
max-width: 100px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TV Show</title>
</head>
<body>
<h1>TV Search</h1>
<input type="text" id="searchField" placeholder="Search a TV Show...">
<ul id="resultsList"></ul>
<ul id="imagesDisplay"></ul>
<div id="errorMessage">
</div>
<script src="script.js"></script>
</body>
</html>

Related

Openweather API linking the searchbar to the actual city chosen from the hard coding part

I am currently working on a weather app using Openweather API, and I'm having a little strugle on creating the function that in the moment that a city is written in the search bar and the button search is pressed, I want the h1 with the class "chosen-location" textcontent to change into the input from the search bar, this thing should happen by changing the value of the variable city into the content from the searchbar. That's how I would do it if I would have some more expierence, but I don't know how to really write all this stuff.
const apikey = `45d2b1974108dfa1128c4ce9991a1f56`;
let city = "Constanta";
let search = document.querySelector('.searchbar');
let button = document.querySelector('.btn');
window.addEventListener('load', ()=>{
let long;
let lat;
let temperatureDescription = document.querySelector('.temperature-description');
let temperatureDegree = document.querySelector('.degree');
let locationTimezone = document.querySelector('.location-timezone');
let icon = document.querySelector('.icon');
if(navigator.geolocation){
navigator.geolocation.getCurrentPosition(position => {
long = position.coords.longitude;
lat = position.coords.latitude;
// what i've done here takes your coordinates and puts them to the variables mentioned
const api = `https://api.openweathermap.org/data/2.5/weather?q=${city}&APPID=${apikey}&units=metric`;
fetch(api)
.then(respones => {
return respones.json();
})
.then(data =>{
console.log(data);
const {temp} = data.main;
const {main} = data.weather[0];
const {country} = data.sys;
// set DOM elements from the API
temperatureDegree.textContent = temp;
temperatureDescription.textContent = main;
locationTimezone.textContent = country;
if(temperatureDescription.textContent === 'Mist'){
document.querySelector('.icon').src='http://openweathermap.org/img/wn/50d#2x.png';
}if(temperatureDescription.textContent === 'Clear Sky'){
document.querySelector('.icon').src='http://openweathermap.org/img/wn/01d#2x.png';
}if(temperatureDescription.textContent === 'Clouds'){
document.querySelector('.icon').src='http://openweathermap.org/img/wn/03d#2x.png';
}if(temperatureDescription.textContent === 'Rain'){
document.querySelector('.icon').src='http://openweathermap.org/img/wn/10d#2x.png';
}if(temperatureDescription.textContent === 'Thunderstorm'){
document.querySelector('.icon').src='http://openweathermap.org/img/wn/11d#2x.png';
}if(temperatureDescription.textContent === 'Snow'){
document.querySelector('.icon').src='http://openweathermap.org/img/wn/13d#2x.png';
}
console.log(temperatureDescription.textContent);
});});
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title> Weather app </title>
</head>
<body>
<div class="location">
<h1 class="location-timezone">Timezone</h1>
<h1 class="chosen-location">Constanta</h1>
<img class= "icon" src="http://openweathermap.org/img/wn/01d#2x.png" alt="weather">
</div>
<div class="search"><input type="text" placeholder="Ex:Chicago" class="searchbar"></div> <button class="btn">Search</button>
<div class="temperature">
<div class="degree-section">
<h2 class="degree">34</h2>
<span> Celsius</span>
</div>
<div class="temperature-description">It's frkin cold</div>
</div>
<script type ="module" src="script.js"></script>
</body>
</html>

ToDoList in JavaScript by classes

I wanted to train classes in Java Script with To Do List but I had some errors.
I want to make it by 4 classes (in separate files) - only for training.
Main.js - to coordinate rest of classes
AddTask.js
RemoveTask.js
SearchTask.js
I have an error with pushing tasks to toDoList in class AddTask.js.
This is code in HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>ToDoList</h1>
<section>
<input type="text">
<button id="start">Add task</button>
</section>
<input type="text" class="search">
<h2>Number of tasks: <span>0</span></h2>
<ul></ul>
<script src="AddTask.js"></script>
<script src="RemoveTask.js"></script>
<script src="SearchTask.js"></script>
<script src="Main.js"></script>
</body>
</html>
This is code in Main.js
class Main {
constructor(){
this.addTask = new AddTask()
this.button=document.getElementById('start')
this.button.addEventListener('click', this.addTask.startGame.bind(this))
this.taskNumber = document.querySelector('h2 span')
this.ul = document.querySelector('body ul')
}
}
const start = new Main()
This is code in AddTask.js
class AddTask {
constructor() {
this.toDoList = []
}
startGame() {
const input = document.querySelector('section input')
const titleTask = input.value;
if (titleTask === "") return alert ('You have to write a task!');
const task = document.createElement('li');
task.innerHTML = titleTask + "<button>Delete</button>";
this.toDoList.push(task)
input.value = ""
return toDoList;
}
}
Now the error is:
AddTask.js:14 Uncaught TypeError: Cannot read properties of undefined (reading 'push') at Main.startGame (AddTask.js:14:19).
Could you tell me what is the problem in that case?
Remove .bind from Main Class and add
this.startGame = this.startGame.bind(this); to the constructorof AddTask
class AddTask {
constructor() {
this.toDoList = [];
this.startGame = this.startGame.bind(this);
}
startGame() {
const input = document.querySelector("section input");
const titleTask = input.value;
if (titleTask === "") return alert("You have to write a task!");
const task = document.createElement("li");
task.innerHTML = titleTask + "<button>Delete</button>";
this.toDoList.push(task);
input.value = "";
return this.toDoList;
}
}

is there a way to assign id or classname to an element through document.createElement?

Im still relatively new to JS. I know i probably shouldnt write my code the way i have done here in the real world, but im only doing this to test my knowledge on for loops and pulling JSON data.
My question is, with the way i have structured my code, is it possible for me to add classnames/Id's to the elements i have made using doc.createElement? for example if i wanted to add custom icons or buttons to each element? I cant seem to think of a way to add them other than having to write out all the HTML and do it that way. Here's my code :
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./styles.css">
<title>Document</title>
</head>
<body>
<section>
</section>
<script src="./app.js"></script>
</body>
</html>
JS
const allCustomers = document.querySelector("section");
let custName = "";
let username = "";
let email = "";
let id = "";
const requestURL = "https://jsonplaceholder.typicode.com/users";
fetch(requestURL)
.then((response) => response.text())
.then((text) => DisplayUserInfo(text));
function DisplayUserInfo(userData) {
const userArray = JSON.parse(userData);
for (i = 0; i < userArray.length; i++) {
let listContainer = document.createElement("div");
let myList = document.createElement("p");
let myListItems = document.createElement("span");
myList.textContent = `Customer : ${userArray[i].name}`;
myListItems.innerHTML =`<br>ID: ${userArray[i].id} <br>Email: ${userArray[i].email} <br>Username: ${userArray[i].username}`;
myListItems.appendChild(myList);
listContainer.appendChild(myListItems);
allCustomers.appendChild(listContainer);
}
}
DisplayUserInfo();
Any pointers would be greatly appreciated as well as any constructive feedback. Thanks
Yes, for sure you can add any attribute for a created element. element.classList.add('class-name-here') for adding class, element.id = 'id-name-here' for adding id.
const allCustomers = document.querySelector("section");
let custName = "";
let username = "";
let email = "";
let id = "";
const requestURL = "https://jsonplaceholder.typicode.com/users";
fetch(requestURL)
.then((response) => response.text())
.then((text) => DisplayUserInfo(text));
function DisplayUserInfo(userData) {
const userArray = JSON.parse(userData);
for (i = 0; i < userArray.length; i++) {
let listContainer = document.createElement("div");
let myList = document.createElement("p");
myList.classList.add('active');
myList.id = 'paragraph'
let myListItems = document.createElement("span");
myList.textContent = `Customer : ${userArray[i].name}`;
myListItems.innerHTML =`<br>ID: ${userArray[i].id} <br>Email: ${userArray[i].email} <br>Username: ${userArray[i].username}`;
myListItems.appendChild(myList);
listContainer.appendChild(myListItems);
allCustomers.appendChild(listContainer);
}
}
DisplayUserInfo();
.active {
color: red;
}
#paragraph {
font-size: 24px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./styles.css">
<title>Document</title>
</head>
<body>
<section>
</section>
<script src="./app.js"></script>
</body>
</html>
is it possible for me to add classnames/Id's to the elements i have
made using doc.createElement
Yes possible with classList for adding class and setAttribute to add id
let listContainer = document.createElement("div");
// To add class
listContainer.className = 'your-class'; //if you have just one
listContainer.classList.add("my-class");//if you want to add multiple
// To add id
listContainer.setAttribute("id", "your_id");
When you use document.createElement it returns an Element. You can use Element attributes and methods to reach what you need. There are some docs for this class on MDN.
This means you can:
> myDiv = document.createElement("div")
<div></div>
> myDiv.id = "test"
'test'
> myDiv
<div id="test"></div>
For classes you can use the attributes className or classList.

how to store my data in local storage as object from what I've got

Two buttons counting and storing data in local storage, just trying to make it store as obj in local storage, but I'm a newbie and couldn't make it work can some1 explain how to do it from what I've got? thank you! don't know if I can just add this here or need to do it from scratch?
const wellbtn = document.querySelector('.wellbtn');
const unwellbtn = document.querySelector('.unwellbtn');
const moodwell = document.querySelector('.moodwell')
const moodunwell = document.querySelector('.moodunwell')
let wellcounter = localStorage.getItem('wellcounter');
let unwellcounter = localStorage.getItem('unwellcounter');
moodwell.innerText = `You felt well ${wellcounter} times`;
moodunwell.innerText = `You felt unwell ${unwellcounter} times`;
const addWellCounter = (() => {
moodwell.innerText = `You felt well ${++wellcounter} times`
localStorage.setItem('wellcounter', wellcounter.toString());
})
const addUnwellCounter = (() => {
moodunwell.innerText = `You felt unwell ${++unwellcounter} times`
localStorage.setItem('unwellcounter', unwellcounter.toString());
})
wellbtn.addEventListener('click', () => {
addWellCounter();
})
unwellbtn.addEventListener('click', () => {
addUnwellCounter();
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My title</title>
</head>
<body>
<h1>How do you feel ?</h1>
<button class="wellbtn">Well</button>
<button class="unwellbtn">Unwell</button>
<p class="moodwell">You felt well 0 times</p>
<p class="moodunwell">You felt unwell 0 times</p>
</body>
</html>

Without clicking the button to fetch data in js, my page fetched data automatically, and there is the second call to button [duplicate]

This question already has answers here:
addEventListener Executing Before Being Clicked
(2 answers)
Closed 2 years ago.
Can anyone help me with that- I am using fetch api here and this is linked to a button ,here I used fetch api for a get request, but the problem is that without clicking the button ,my data is fetched from the api.
When I clicked the button to fetch data first time, it works perfectly but after that on reload my data is fetched automatically without clicking button. what's the problem here and how to fix it?
easyhttp.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>easy http</title>
</head>
<body>
<ol id="getRequestData">
</ol>
<button id="btn1">get</button>
<button id="btn2">post</button>
<button id="btn3">put</button>
<button id="btn4">delete</button>
<script src="easyHttpWithFetch.js"></script>
</body>
</html>
easyHttpWithFetch.js
document.getElementById("btn1").addEventListener("click",get("https://jsonplaceholder.typicode.com/posts"));
function get(url){
fetch(url)
.then(response => response.json())
.then((data) => {
let str = "";
data.forEach(element => {
str += '<li><ol type="a">';
for (const key in element) {
if (Object.hasOwnProperty.call(element, key)) {
const value = element[key];
str+= `<li>${value}</li>`;
}
}
str += '</ol></li>';
let getRequestData = document.getElementById("getRequestData");
getRequestData.innerHTML = str;
});
}).catch((err) => {
console.log(err);
});
}
The second parameter of the addEventListener() is the function name that we want to call when the click occurs. But you are currently trying to execute the get() method by passing the url parameter immediately.
That's why get() is first called initially when btn1 is attached to the click event.
To fix this, try to use the arrow function.
document.getElementById("btn1").addEventListener("click", () => get("https://jsonplaceholder.typicode.com/posts"));
function get(url) {
fetch(url)
.then(response => response.json())
.then((data) => {
let str = "";
data.forEach(element => {
str += '<li><ol type="a">';
for (const key in element) {
if (Object.hasOwnProperty.call(element, key)) {
const value = element[key];
str += `<li>${value}</li>`;
}
}
str += '</ol></li>';
let getRequestData = document.getElementById("getRequestData");
getRequestData.innerHTML = str;
});
}).catch((err) => {
console.log(err);
});
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>easy http</title>
</head>
<body>
<ol id="getRequestData">
</ol>
<button id="btn1">get</button>
<button id="btn2">post</button>
<button id="btn3">put</button>
<button id="btn4">delete</button>
</body>
</html>

Categories