How to get const from forEach method in javascript? - javascript

I have django application with quiz model:
class Quiz(models.Model):
name = models.CharField(max_length=50)
topic = models.CharField(choices=TOPICS, max_length=50)
number_of_questions = models.IntegerField(validators=[MinValueValidator(1)])
time = models.IntegerField(help_text="duration of quiz in minutes", default=5)
pass_score = models.IntegerField(help_text="score required to pass in %", default=90, validators = [MaxValueValidator(100), MinValueValidator(0)])
difficulty = models.CharField(choices=DIFFICULTY_CHOICES, max_length=10)
I get it in view:
def quiz_view(request, pk):
quiz = models.Quiz.objects.get(pk=pk)
return render(request, 'quizes/quiz.html', {'obj':quiz})
Then I get data of obj in html:
{% for obj in object_list %}
<button class="modal-button" data-pk="{{ obj.pk }}" data-name="{{ obj.name }}" data-topic="{{ obj.topic }}" data-questions="{{ obj.number_of_questions }}" data-difficulty="{{ obj.difficulty }}" data-time="{{ obj.time }}" data-pass="{{ obj.pass_score }}">
{{ obj.name }}
</button>
{% endfor %}
<div id="modal"></div>
Then I get data from button in javascript forEach method:
let modal = document.getElementById('modal')
const modalBtns = [...document.getElementsByClassName('modal-button')]
modalBtns.forEach(modalBtn => modalBtn.addEventListener('click', ()=>{
const pk = modalBtn.getAttribute('data-pk')
const name = modalBtn.getAttribute('data-name')
const topic = modalBtn.getAttribute('data-topic')
const numQuestions = modalBtn.getAttribute('data-questions')
const difficulty = modalBtn.getAttribute('data-difficulty')
const passScore = modalBtn.getAttribute('data-pass')
const time = modalBtn.getAttribute('data-time')
if(modal.classList.contains('close-modal')){
modal.classList.remove('close-modal')
}
modal.classList.add('open-modal')
modal.innerHTML = `
<p class="text">Are you sure you want to open</p><p class="name_of_quiz"><b>${name}?</b></p>
<ul class="description">
<li>Topic: ${topic}</li>
<li>Questions: ${numQuestions}</li>
<li>Difficulty: ${difficulty}</li>
<li>Score to pass: ${passScore}%</li>
<li>Time to solve: ${time} min</li>
</ul>
<div class="buttons-container">
<button class="close-button" onclick="close_modal()">Close</button>
<button class="proceed-button" id='start_button' onclick="startQuiz()">Yes</button>
</div>
`
}))
So when user clicks on button it sets open-modal:
.open-modal{
visibility: visible !important;
}
And we can see it. Then when I click 'proceed-button', I should get pk by running startQuiz():
function startQuiz(){
console.log(pk)
}
But I get an error:
`'pk' is not defined'.
Can I somehow get pk from forEach method?

i found your problem. You can't use a const. Constants have a block scope. Use parameters instead. A snippet of your javascript could be:
let modal = document.getElementById('modal')
const modalBtns = [...document.getElementsByClassName('modal-button')]
modalBtns.forEach(modalBtn => modalBtn.addEventListener('click', ()=>{
const pk = modalBtn.getAttribute('data-pk')
const name = modalBtn.getAttribute('data-name')
const topic = modalBtn.getAttribute('data-topic')
const numQuestions = modalBtn.getAttribute('data-questions')
const difficulty = modalBtn.getAttribute('data-difficulty')
const passScore = modalBtn.getAttribute('data-pass')
const time = modalBtn.getAttribute('data-time')
if(modal.classList.contains('close-modal')){
modal.classList.remove('close-modal')
}
modal.classList.add('open-modal')
modal.innerHTML = `
<p class="text">Are you sure you want to open</p><p class="name_of_quiz"><b>${name}?</b></p>
<ul class="description">
<li>Topic: ${topic}</li>
<li>Questions: ${numQuestions}</li>
<li>Difficulty: ${difficulty}</li>
<li>Score to pass: ${passScore}%</li>
<li>Time to solve: ${time} min</li>
</ul>
<div class="buttons-container">
<button class="close-button" onclick="close_modal()">Close</button>
<button class="proceed-button" id='start_button' onclick="startQuiz(${pk})">Yes</button>
</div>
`
}))
function startQuiz(pk){
console.log(pk)
}
With some value types it can happen that it doesn't work properly. If it doesn't work, write a comment with the type of pk.

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;
}```

How to get one value (clicked one) from for loop in JS addEventListener Django project

Im trying connect JS inside my Django project I got message in console that
HTMLCollection(2) [p.currency-one, p.currency-one]
HTMLCollection(2) [input.amount-one, input.amount-one]
app.js:21 Uncaught TypeError: c1.addEventListener is not a function
at app.js:21:4
(anonymous) # app.js:21
JS file
const c1 = document.getElementsByClassName("currency-one");
const c2 = document.getElementById("currency-two");
const amount1 = document.getElementsByClassName("amount-one");
const amount2 = document.getElementById("amount-two");
const swap = document.getElementById("swap");
const theRate = document.getElementById("rate");
console.log(c1,amount1)
function calculate() {
const curr1 = c1.innerHTML;
const curr2 = c2.innerHTML;
const rate = parseInt(amount1.value) / parseFloat(amount2.innerHTML);
theRate.innerText = `You can buy maximum -> you wallet money ${amount1.value} ${curr1} = ${rate} ${curr2}`;
}
// THIS PART OF THE CODE does not know how to get two pieces of information from one //class, how to get through it ?
c1.addEventListener("change", calculate);
amount1.addEventListener("input", calculate);
c2.addEventListener("change", calculate);
amount2.addEventListener("input", calculate);
swap.addEventListener("click", () => {
const flash = c1.value;
c1.value = c2.value;
c2.value = flash;
calculate();
});
view.py
def a(request,crypto_name, fiat_currency=None):
buttons = [
{"currency_type": "USD", "active": "", "display_text": "USD"},
{"currency_type": "EUR", "active": "", "display_text": "Euro"},
{"currency_type": "CNY", "active": "", "display_text": "Chinese Yuan"},
{"currency_type": "JPY", "active": "", "display_text": "Japanese Yen"},
]
for button in buttons:
if button['currency_type'] == fiat_currency:
button['active'] = 'active'
crypto_detail_view = load_detail_crypto(crypto_name,fiat_currency)
user_purchased_currencies = UserPurchasedCurrencies.objects.filter(user = request.user)
user_walet_info_amount_and_name = [x for i in user_purchased_currencies for x in (i.currency_amount,i.currency)]
x = crypto_name
context = {
"crypto_detail_view" : crypto_detail_view,
"buttons" : buttons,
"crypto_name" : crypto_name,
"fiat_currency" : fiat_currency,
"user_walet_info_amount_and_name" : user_walet_info_amount_and_name,
"user_purchased_currencies" : user_purchased_currencies,
}
return render(request, 'web/a.html', context)
html
{% extends "web/layout.html" %}
{% block body %}
<br><br><br>
<div id="jumbotron" class="jumbotron" style="text-align: center; margin-top:-50px">
<h1 id="devise" class="display-5">Devise </h1>
<h5>Exchange Rate Converter</h5>
<img src="image.jpg" class="image" style="width:100px; margin-bottom:-50px; " >
</div>
<div class="container">
<div class="page-header" id="banner">
<div class="row">
<div class="col-sm-15">
<h1 style="align-content: center;"> </h1>
<p class="lead" style="margin-left:280px; font-size:2rem">
</p>
</div>
</div>
</div>
<div class="row">
{% for item in buttons %}
{% for money_purchased in user_purchased_currencies %}
{% if item.currency_type != money_purchased.currency %}
{% else %}
<div class="col-4 col-md-4" >
<p class="currency-one">{{item.display_text}}</p>
<a href="{% url 'a' crypto_name=crypto_name fiat_currency=item.currency_type %}" class="btn btn-outline-dark {{item.active}}" role="button" >{{item.display_text}}</a>
</div>
<input type="number" class="amount-one" value="{{money_purchased.currency_amount}}" style="width:100%" />
{% endif %}
{% endfor %}
{% endfor %}
</div>
<br>
<div class="swap-btn">
<button type="button" id="swap" class="btn btn-outline-primary mx-auto d-block" >Swap <i class="fa fa-refresh" aria-hidden="true"></i></button>
</div>
<div class="rate" id="rate"></div>
<br>
{% for crypto in crypto_detail_view %}
<div class="container">
<div class="currency">
<p class="form-control" id="currency-two">{{crypto.name}}</p>
<br>
<p class="form-control" type="number" id="amount-two" style="width:100%">{{crypto.price}}</p>
</div>
</div>
{% endfor %}
<script src="/static/js/app.js"></script>
{% endblock %}
I would like to get only this two but just those clicked values
c1.addEventListener("change", calculate);
amount1.addEventListener("input", calculate);
part of the code in views checks what currencies the user has purchased , when the user clicks on USD for example, he will received how much USD he has to use and when he already selected / clicked, then the code in JS should select the appropriate amount and currency name.
How to do it? with the use of loops?
<div class="row">
{% for item in buttons %}
{% for money_purchased in user_purchased_currencies %}
{% if item.currency_type != money_purchased.currency %}
{% else %}
<div class="col-4 col-md-4" >
<p class="currency-one">{{item.display_text}}</p>
<a href="{% url 'a' crypto_name=crypto_name fiat_currency=item.currency_type %}" class="btn btn-outline-dark {{item.active}}" role="button" >{{item.display_text}}</a>
</div>
<input type="number" class="amount-one" value="{{money_purchased.currency_amount}}" style="width:100%" />
{% endif %}
{% endfor %}
{% endfor %}
</div>
Update
Now, no matter what I click the USD or the Japanese Yen I get the last currency from the for loop, how to fix it?
let c1 = document.getElementsByClassName("currency-one");
let c2 = document.getElementById("currency-two");
let amount1 = document.getElementsByClassName("amount-one");
const amount2 = document.getElementById("amount-two");
const swap = document.getElementById("swap");
const theRate = document.getElementById("rate");
function calculate(curr1,amount11) {
//let curr1 = c1.innerHTML;
console.log("C1", curr1, i)
const curr2 = c2.innerHTML;
const rate = amount11 / parseFloat(amount2.innerHTML);
theRate.innerText = `You can buy maximum -> you wallet money ${amount11} ${curr1} = ${rate} ${curr2}`;
}
for(var i = 0; i < c1.length; i++) {
console.log("dsada",c1[i].innerHTML,amount1[i].value)
let curr1 = c1[i].innerHTML;
let amount11 = parseInt(amount1[i].value) ;
c1[i].addEventListener("change", calculate(curr1,amount11));
amount1[i].addEventListener("input", calculate(curr1,amount11));
}
c2.addEventListener("change", calculate);
amount2.addEventListener("input", calculate);
swap.addEventListener("click", () => {
const flash = c1.value;
c1.value = c2.value;
c2.value = flash;
calculate();
});
one variable should be outside the loop or ?
UPDATE2
let c1 = document.getElementsByClassName("currency-one");
let c2 = document.getElementById("currency-two");
let amount1 = document.getElementsByClassName("amount-one");
const amount2 = document.getElementById("amount-two");
const swap = document.getElementById("swap");
const theRate = document.getElementById("rate");
function calculate(c1,amount1) {
let curr1 = c1.innerHTML;
const curr2 = c2.innerHTML;
console.log(amount1.value,parseInt(amount1.value),amount1)
const rate = parseInt(amount1.value) / parseFloat(amount2.innerHTML);
theRate.innerText = `You can buy maximum -> you wallet money ${parseInt(amount1.value) } ${curr1} = ${rate} ${curr2}`;
}
for(var i = 0; i < c1.length; i++) {
c1[i].innerHTML.click = function (){
console.log("11111")
c1.textContent = this.innerHTML;
}
amount1[i].value.click = function (){
console.log("22222")
amount1.textContent = this.value;
}
c1[i].addEventListener("change", calculate);
amount1[i].addEventListener("input", calculate);
}
c2.addEventListener("change", calculate);
amount2.addEventListener("input", calculate);
swap.addEventListener("click", () => {
const flash = c1.value;
c1.value = c2.value;
c2.value = flash;
calculate();
});
Only this part of the code do something
c1[i].addEventListener("change", calculate);
amount1[i].addEventListener("input", calculate);
I receive a info in console log
undefined NaN HTMLCollection(3) [input.amount-one, input.amount-one, input.amount-one]
I still have no idea how to make this code functional,
I don't know how to get to these values in the for loop and use the selected one in the calculator function?
the problem exists here:
c1.addEventListener("change", calculate);
amount1.addEventListener("input", calculate);
c2.addEventListener("change", calculate);
amount2.addEventListener("input", calculate);
you are trying to use the "addEventListener" context on "getElementsByClassName" and this getElementsByClassName refers to many of the elements since you put these elements in for loop so, this className will be reading as an array.
the solution is:
you should loop these classes which are p.currency-one and input.amount-one as it said in the console then you can apply your eventListener function after that
for example:
const c1 = document.getElementsByClassName("currency-one");
let target = document.getElementById("div-for-example")
for(var i = 0; i < c1.length; i++) {
// Update
c1[i].click = function () {
target.textContent = this.value;
}
}

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.

Cannot pass Object as param to onClick while iterating with innerHTML

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>

fail to modify content of template

<template id="entry-temp">
<li id="movie-list">
<span id="movie-info"> <span id = "li-movie-title"></span> (<span id = "li-movie-year"></span>) - <span id = "li-movie-rating"></span></span>
<button type="submit" id="movie-edit" name="movie-edit">edit</button>
<button type="submit" id="movie-delete" name="movie-delete">delete</button>
</li>
</template>
function appendMovie(title, year, rating) {
let template = document.querySelector("#entry-temp");
let tempNode = document.importNode(template.content, true);
tempNode.querySelector("#li-movie-title").innerHTMl = title;
tempNode.querySelector("#li-movie-year").innerHTMl = year;
tempNode.querySelector("#li-movie-rating").innerHTMl = rating;
let moviePanel = document.getElementById("movie-panel");
alert(tempNode.innerHTMl);
moviePanel.appendChild(tempNode);
}
The alert gives me undefined, and tempNode is a document fragment.
Also, is there a better way to print out the tag in JavaScript for debugging?
For example, How can I check if I really write title, year, and rating?

Categories

Resources