Cannot pass Object as param to onClick while iterating with innerHTML - javascript

I am currently iterating through a list of movies and want to be able to make each element clickable and pass their respective movie information to the click event.
Here is how I iterate through my data. I want to be able to pass the movie information to the click event so that when I click on a movie, I can display its information :
const APIKEY = 'api_key=blabla....';
const BASE_URL = 'https://api.themoviedb.org/3';
const API_URL = BASE_URL + '/discover/movie?sort_by=popularity.desc&' + APIKEY;
const IMG_URL = 'https://image.tmdb.org/t/p/w500';
const SEARCH_URL = BASE_URL + '/search/movie?' + APIKEY;
const main = document.getElementById('main')
const form = document.getElementById('form')
const search = document.getElementById('search')
getMovies(API_URL);
function getMovies(url) {
fetch(url).then(res => res.json()).then(data => {
showMovies(data.results);
console.log(data.results)
})
}
function showMovies(data){
main.innerText = '';
data.forEach((movie, index) => {
let {title, poster_path, release_date, overview} = movie;
let movieEl = document.createElement('div');
movieEl.classList.add('movie');
movieEl.innerHTML = `
<div onclick="showMovieInfo(${movie[index]})" style="cursor: pointer;">
<img src="${IMG_URL + poster_path}" alt="${title}">
<div class="movie-info">
<h3>${title}</h3>
<span>${release_date.slice(0,4)}</span>
</div>
<div class="overview">
${overview}
</div>
</div>
`
main.appendChild(movieEl)
})
}
For Now i just want to be able to console.log the movie info for each
function showMovieInfo(movie) {
console.log(movie)
}
Currently I get this error when I click on an element: Uncaught SyntaxError: Unexpected identifier
Do you guys know what I could do to make it work?

The problem here ist that the "movie" object don´t exist in the "innerHTML" context. One Solution would be to serialise the movie Object or pass the Index and than get the Object from the data Array.
You can´t pass an Object to innerHTML so you have to pass a Primitive values like string or number.
const main = document.getElementById('main');
const IMG_URL = "/"
const data = [{title: "New Movie", poster_path:"",release_date:"2021-10-31", overview:"nice movie" }];
function showMovieInfo(movieId){
console.log(data[movieId])
}
function showMovies(data){
main.innerText = '';
data.forEach((movie, index) => {
let {title, poster_path, release_date, overview} = movie;
let movieEl = document.createElement('div');
movieEl.classList.add('movie');
movieEl.innerHTML = `
<div onclick="showMovieInfo(${index})" style="cursor: pointer;">
<img src="${IMG_URL + poster_path}" alt="${title}">
<div class="movie-info">
<h3>${title}</h3>
<span>${release_date.slice(0,4)}</span>
</div>
<div class="overview">
${overview}
</div>
</div>
`
main.appendChild(movieEl)
})
}
showMovies(data);
<div id="main">
</div>

Related

TMDB pagination JavaScript

I m want implement pagination with js and apirest from themoviedb.
Response give me a total_pages and total_results. I ve 2 buttons, prev and next.
Thanks in advance for help me to understand. Best regards.
I´m student and now i want create my repo as exercise and practice
My full code
//buttons
const btnAtras = document.getElementById('btnAtras')
const btnAdelante = document.getElementById('btnAdelante')
//api props
const key ='MyKey';
const lang ='es-ES';
let page =1
const fetch1 = fetch('https://api.themoviedb.org/3/movie/now_playing?api_key='+key+'&language='+lang+'&page='+page).then(resp=> resp.json())
const fetch2 = fetch('https://api.themoviedb.org/3/genre/movie/list?api_key='+key+'&language='+lang).then(resp=>resp.json())
//multifetch request
const allData = Promise.all([fetch1,fetch2])
allData.then(data=>{
let genres = data[1].genres
let movies = data[0].results
let currentPage = data[0].page;
let totalPages = data[0].total_pages
console.log(currentPage)
console.log(totalPages)
//map for taking all genre_ids to resolve genre_names
for (let movie of movies) {
movie.genres = genres.filter((item) => ((movie.genre_ids.indexOf(item.id) >= 0)));
movie.genre_names = movie.genres.map(item => item.name);
}
//getting all data
getCardFilm(movies);
})
//function to create each card template
function getCardFilm (data){
const cardContent = document.getElementById('playingNow');
let content = '';
const _baseUrlImg = 'https://image.tmdb.org/t/p/original';
data.forEach(film =>{
const {title,genre_names, poster_path, release_date, overview, id} = film;
content += `
<div class='card m-2' style='width: 22rem;' >
<img src='${_baseUrlImg+poster_path}' class='card-img-top' style='height:460px;width:100%;' alt='Imágen de la pelicula'>
<div class='card-header text-start'style='height: 6rem;'>
<h5 class='card-title'>${title}</h5>
<p class='card-text text-muted'>Lanzamiento: ${release_date}</p>
</div>
<div class='card-body text-start' id='linkFilm'>
<p class='card-text m-0'>${overview}</p>
</div>
<div class="card-footer text-muted " style='width:100%;
height:4rem;'>
<span class='text-center text-dark'>
${genre_names}
</span>
</div>
</div>
`
})
cardContent.innerHTML=content;
}```

Use id from Template strings item

i'm having a trouble using the id from a template string item
const elementoParaInserirJogosNaLista = document.getElementById("listaJogos");
function exibirJogosNaTela(listaDeJogos) {
elementoParaInserirJogosNaLista.innerHTML = "";
listaDeJogos.forEach((jogo) => {
elementoParaInserirJogosNaLista.innerHTML += `
<div class="jogo">
<a href="paginajogo.html">
<img class="jogo__imagem" src="${jogo.imagem}" alt="${jogo.titulo}" />
</a>
<h2 class="jogo__titulo">${jogo.titulo}</h2>
<p class="jogo__preco" id="preco">R$${jogo.preco}<a ><img class="jogo__carrinho" id="addCarrinho" src="./images/addcart.png" alt="Adicionar ao carrinho"/></p><a/>
</div>
`;
});
}
i've tried to use the id "addCarrinho" and nothing happens
i'm newb on developing
const botoesAddCarrinho = [];
botoesAddCarrinho = document.querySelectorAll(".jogo__carrinho");
botoesAddCarrinho.forEach((evento) =>
evento.addEventListener("click", addNoCarrinho)
);
function addNoCarrinho () {
console.log('ok')
}
i've changed the selector to by the class, but nothings happens, is like the nothing was selected
i'm using the exibirNaTela on the fetch with the json
let jogos = [];
const endpointDaAPI ="jogos.json"
getBuscarJogosDaAPI();
async function getBuscarJogosDaAPI() {
const respost = await fetch(endpointDaAPI);
jogos = await respost.json();
exibirJogosNaTela(jogos.jogos);
}

JavaScript :Ajax - Symfony 6 : trying to send form with plain js ajax

I have a little problem or a big one, I don't know. I'm trying to send a form with ajax with Symfony, and native JavaScript, but I don't really know how. I managed to do ajax with GET request to try to find a city (which is included in this form).
So I've got my form, I also want to send 2 arrays 1 for images (multiple images with different input) the input are created with js via CollectionType::class, then I'm putting my images in array which I want to send.
And the other array is for the city I want my product to be in. I've got an input text and via ajax it's searching city then by clicking on the city I've got a function putting it on an array.
but now I find difficulties trying to send it everything I found on the web mostly uses jQuery.. but I want to learn JavaScript so I believe I have to train with native first.
so I tried to send my form, but nothing happened when I submit it, not even an error, it just reload the page, and in my console I've got a warning for CORB issues I think it's due to my browser blocking my request because something is wrong in it?
I'm trying to find a way to send it and save it in my database.
so here's the code:
{% extends "base.html.twig" %}
{% block body %}
<div class="container">
<div class="row">
<div class="col-lg-6 mx-auto mt-5">
{{form_start(form)}}
{{form_errors(form)}}
{{form_row(form.title)}}
{{form_row(form.description)}}
{{form_row(form.surface)}}
{{form_row(form.piece)}}
{{form_row(form.type)}}
<div class="container">
<div class="select-btn">
<span class="btn-text d-flex">
<input type="text" oninput="getData(this.value)" class="rel" name="ville" id="">
<span class="arrow-dwn">
<i class="fa-solid fa-chevron-down"></i>
</span>
</span>
</div>
<ul class="list-items js-result"></ul>
</div>
<button type="button" class="btn btn-primary btn-new opacity-100" data-collection="#foo">ajouter une image</button>
<div id="foo" class="row" data-prototype="{{include ("include/_Addimage.inc.html.twig", {form: form.image.vars.prototype})|e("html_attr")}}" data-index="{{form.image|length > 0 ? form.image|last.vars.name +1 : 0}}">
{% for image in form.image %}
<div class="col-4">
{{ include ("include/_Addimage.inc.html.twig", {form: image}) }}
</div>
{{form_errors(form.image)}}
{% endfor %}
</div>
<div class="col-4 mt-5">
{{form_row(form.submit)}}
</div>
{{form_widget(form._token)}}
{{form_end(form, {render_rest: false})}}
</div>
</div>
</div>
{% endblock %}
here the code of my JavaScript, everything is in my twig file, because as you will see I added eventListener on some input, I didn't see a better way maybe someone can correct me.
{% block javascripts %}
<script type="text/javascript">
/////////////// GET INPUT TEXT VALUE AND SHOW A LIST OF CITIES
function getData(text) {
const param = new URLSearchParams();
param.append('text', text);
const url = new URL(window.location.href);
fetch(url.pathname + "?" + param.toString() + "&ajax=1", {
header: {
"X-Requested-With": "XMLHttpRequest"
}
})
.then(response => response.json())
.then(data => {
handle_result(data);
});
}
////////////////////////////// CREATE MY OPTIONS WITH CITIES NAME
function handle_result(response)
{
let result_div = document.querySelector(".js-result");
let str = "";
for (let i = response.length - 1; i >= 0; i--) {
str += "<option" + ' ' + "onclick=" + "addTag(this.value)" + ' ' + "class=" + "item" + ' ' + "value=" + response[i].ville + ">" + response[i].ville + "</option>";
}
result_div.innerHTML = str;
};
// //////////////////////////// ADD THE CITY NAME IN A CONTAINER WHEN I USER CLICK ON IT
const selectBtn = document.querySelector(".select-btn");
const rel = document.querySelector(".rel");
items = document.querySelectorAll(".item");
rel.addEventListener("click", () => {
selectBtn.classList.toggle("open");
});
function createTag(label) {
const div = document.createElement('div');
div.setAttribute('class', 'tag');
const span = document.createElement('span');
span.innerText = label;
const closeBtn = document.createElement('i');
closeBtn.setAttribute('data-item', label);
closeBtn.setAttribute('onclick', 'remove(this)');
closeBtn.setAttribute('class', 'material-icons');
closeBtn.innerHTML = 'close';
div.appendChild(span);
div.appendChild(closeBtn);
return div;
}
btnText = document.querySelector(".btn-text");
let tags = [];
function addTags()
{
reset();
for (let a of tags.slice().reverse()) {
const tag = createTag(a);
selectBtn.prepend(tag);
}
}
function addTag(value) {
input = document.querySelector('.rel');
console.log(input);
if (tags.includes(value)) {
alreadyExist(value);
}
else {
tags.shift();
tags.push(value);
addTags();
}
input.value = "";
}
function alreadyExist(value) {
const index = tags.indexOf(value);
tags = [
... tags.slice(0, index),
... tags.slice(index + 1)
];
addTags();
}
function reset() {
document.querySelectorAll('.tag').forEach(function (tag) {
tag.parentElement.removeChild(tag);
})
}
function remove(value) {
const data = value.getAttribute('data-item');
const index = tags.indexOf(data);
tags = [
... tags.slice(0, index),
... tags.slice(index + 1)
];
addTags();
}
//////////////////////////////////////////////////////// CREATING IMAGE ARRAY TO SEND WITH AJAX REQUEST ?
images = [];
function image_to_array(value) {
if(!images.includes(value))
{
images.push(value);
}else{
return false;
}
}
const form =
{
title: document.getElementById('product_form_title'),
description: document.getElementById('product_form_description'),
surface: document.getElementById('product_form_surface'),
piece: document.getElementById('product_form_piece'),
type: document.getElementById('product_form_type'),
}
const submit = document.getElementById('submit', () => {
const request = new XMLHttpRequest();
const url = new URL(window.location.href);
const requestData =
`
title=${form.title.value}&
description=${form.description.value}&
surface=${form.surface.value}&
piece=${form.piece.value}&
image=${JSON.stringify(images)}&
type=${JSON.stringify(tags)}&
ville=${tags}
`;
fetch(requestData , url.pathname ,{
header: {
"X-Requested-With": "XMLHttpRequest"
}
})
request.addEventListener('load', function(event) {
console.log(requestData);
});
request.addEventListener('error', function(event) {
console.log(requestData);
});
});
////////////////////////////// CREATE NEW FILE INPUT
const newItem = (e) => {
const collectionHolder = document.querySelector(e.currentTarget.dataset.collection);
const item = document.createElement('div');
item.classList.add('col-4');
item.innerHTML = collectionHolder.dataset.prototype.replace(/__name__/g, collectionHolder.dataset.index);
item.querySelector('.btn-remove').addEventListener('click', () => item.remove());
collectionHolder.appendChild(item);
collectionHolder.dataset.index ++;
}
document.querySelectorAll('.btn-new').forEach(btn => btn.addEventListener('click', newItem));
</script>
{% endblock %}
here my controller but I don't think it is the issue, I didn't finish it since I'm quite lost on the js part
class AdminController extends AbstractController
{
#[Route('/admin/create_product', name: 'create_product', methods: ['POST', 'GET'])]
public function createProduct(EntityManagerInterface $em, SluggerInterface $slugger, Request $request, LieuxRepository $villeRepo, SerializerInterface $serializer): Response
{
$product = new Product;
$ville = new Lieux;
$form = $this->createForm(ProductFormType::class, $product);
$form->handleRequest($request);
$list = $villeRepo->findAll();
$query =$request->get('text');
if($request->get('ajax')){
return $this->json(
json_decode(
$serializer->serialize(
$villeRepo->handleSearch($query),
'json',
[AbstractNormalizer::IGNORED_ATTRIBUTES=>['region', 'departement', 'products']]
), JSON_OBJECT_AS_ARRAY
)
);
}
if($request->isXmlHttpRequest())
{
if ($form->isSubmitted() && $form->isValid()) {
$product->setCreatedAt(new DateTime());
$product->setUpdatedAt(new DateTime());
$product->setVille($form->get('ville')->getData());
$product->setType($form->get('type')->getData());
$em->persist($product);
$em->flush();
}
}
return $this->render(
'admin/create_product.html.twig',
['form' => $form->createView() ]
);
}
hope it's clear, thank you

click event listener method is not working on a specific div

I am trying to add an event listener to my "degree section div" but it is not working nor am I getting any errors. I have tried multiple ways of traversing the DOM to reach the "degree-section" div but to no avail.
Any kind of help is welcome and appreciated
Code:
let city = document.querySelector('#city');
let searchbtn = document.querySelector('.search-btn');
let city_name = document.querySelector('.city-name');
let temp = document.querySelector('.temp');
let feels_like = document.querySelector('.feels-like');
let humidity = document.querySelector('.humidity');
let locationIcon = document.querySelector('.weather-icon');
let checkbox = document.getElementById('celcius');
let weather_sec = document.querySelector('.weather-info');
let degree_section = weather_sec.firstElementChild;
let degree_section_span = degree_section.getElementsByTagName('span')[0];
//let wind = document.querySelector('.wind');
async function getUrl(city) {
try {
let theUrl = url + city + '&appid=' + apiKey;
let response = await fetch(theUrl, {
mode: 'cors'
})
let data = await response.json();
//Get data from api and change html content based on the recieved data
let temp_data = data.main.temp
temp.textContent = temp_data;
let feels_like_data = data.main.feels_like;
feels_like.textContent = feels_like_data + "K";
let humidity_data = data.main.humidity;
humidity.textContent = humidity_data;
let {
icon
} = data.weather[0];
locationIcon.innerHTML = `<img src="icons/${icon}.png">`;
//change K to C
degree_section.addEventListener('click', () => {
//logging a message just to check if it is working
console.log("c")
})
} catch (err) {
let error = document.createElement('span')
error.className = "error";
error.textContent = "Location does not exist"
let top_center_div = document.querySelector('.top-center')
top_center_div.appendChild(error)
city_name.textContent = "No city found"
}
}
searchbtn.addEventListener('click', (e) => {
let cityName = city.value;
city_name.textContent = cityName
console.log(cityName)
getUrl(cityName)
})
<body>
<div class="loc-container">
<div class="location">
<h1 class="city-name">City</h1>
<div class="weather-icon"><img src="icons/unknown.png" /></div>
</div>
</div>
<div class="weather-info">
<div class="degree-section">
<h2 class="temp">0.0</h2>
<span>K</span>
</div>
<div class="info-section">
<div class="info-flex">
<h3 class="feels-like">0K</h3>
<h4>Feels Like</h4>
</div>
<div class="info-flex">
<h3 class="humidity">0</h3>
<h4>Humidity</h4>
</div>
<div class="info-flex">
<h3 class="wind">0</h3>
<h4>Wind</h4>
</div>
</div>
</div>
<div class="top-center">
<div class="form">
<input type="text" name="city" id="city" required>
<label for="city" class="label-name"><span class="search-name">Search City...</span></label>
</div>
<!-- <i class="fas fa-search search-btn"></i> -->
<i class="material-icons search-btn" style="font-size: 35px;">search</i>
</div>
<script src="weather.js"></script>
</body>
This is what "data" looks like
{"coord":{"lon":72.8479,"lat":19.0144},"weather":[{"id":711,"main":"Smoke","description":"smoke","icon":"50d"}],"base":"stations","main":{"temp":303.14,"feels_like":303.45,"temp_min":301.09,"temp_max":303.14,"pressure":1014,"humidity":45},"visibility":2500,"wind":{"speed":3.09,"deg":120},"clouds":{"all":20},"dt":1638773692,"sys":{"type":1,"id":9052,"country":"IN","sunrise":1638754125,"sunset":1638793848},"timezone":19800,"id":1275339,"name":"Mumbai","cod":200}
Thank you in advance!
I believe the problem is with
let degree_section_span = degree_section.getElementsByTagName('span')[0];
since it selects the wrong element. Try changing it to
let degree_section_span = weather_sec.querySelector('.check');
and see if it works. You can also change the variable name to something more appropriate, while you're at it.
EDIT:
I think this is what you're trying to do. For the sake of siplicity , I removed everything not related to temp:
let target = weather_sec.querySelector("div.check"),
temp_data = data.main.temp;
temp.textContent = temp_data;
target.addEventListener('click', () => {
cel = parseInt(temp_data) - 273.15;
temp.textContent = cel.toFixed(2);
temp.nextElementSibling.textContent = "C";
});
So after 48hrs of debugging I finally figured out what is wrong. If you see in my HTML I have a div.top-center at the bottom. And due to some dimension issues in my css file the height of div.top-center spanned the entire page so essentially all of my divs were being wrapped inside div.top-center so even if I assigned a click event to my div.degree-section the target was always div.top-center and that is why the click event was not showing the proper output.

Using fetch results as function parameters

i have fetchTeam(teamName) function which gets an array of players and displays them in HTML. and another function that takes a player name as a parameter and displays the player stats. Something like this....
let result = document.getElementById("result");
let teamName;
const fetchTeam = async (teamName) => {
teamName = document.getElementById("teamName").value;
const response = await fetch(`http://localhost:3000/${teamName}`);
const data = await response.json();
let team = data.teamStats;
let players = data.playerStats;
const teamName = team[0].Name;
const logo = team[0].Logo;
const WL = team[0].WL;
result.innerHTML = `
<br><div class="top">
<h3>${teamName}</h3>
<h4>Win / Loss: ${WL}</h4>
<img src=${logo}></div>
<div class="flex-container">
<div class="flex-child">
<button class='name' onclick="fetchPlayer("${players[0][0].Player}")> ${players[0][0].Player} </button> ...
`
That all works fine except the onclick fetchPlayer function at the bottom.... Heres the code for that:
const results = document.getElementById("results");
const fetchPlayer = async (player) => {
const response = await fetch(`https://get-player.herokuapp.com/${player}`);
const data = await response.json();
results.innerHTML = `
<br>
<div class="layout">
<div class="child"><img src="${data.sprite}[0]"><br>${data.mons[0]}</div>
`
As you can see, i want to display the team members and then clicking on a member name will show their stats.
edit: format
There are several issues in your code.
First, you redeclare teamName in your fetchTeam function. That cannot work.
const fetchTeam = async (teamName) => {
teamName = document.getElementById("teamName").value;
...
const teamName = team[0].Name;
}
Second, your button syntax is incorrect :
<button class='name' onclick="fetchPlayer("${players[0][0].Player}")>
should be
<button class='name' onclick="fetchPlayer('${players[0][0].Player}')">
Third, as pointed out in this answer, in your fetchPlayer function
<img src="${data.sprite}[0]"> should be <img src="${data.sprite[0]}">
In the fetchPlayer function,
Change <img src="${data.sprite}[0]"> to <img src="${data.sprite[0]}">

Categories

Resources