document.querySelector returns null - javascript

I use the querySelector in JS to select html markup that I filled in with a JS script. However, anytime I try to store the divs with a class of .card in the const questionCard, I get null.
Why can't I select the cards?
HTML:
<div class='card-container'></div>
JS:
const questionBlock = document.querySelector('.card-container');
const questionCard = document.querySelector('.card');
function build() {
let output = [];
...some unimportant code here...
output.push(
`
<div class='card'>
<div class='question'>${current.question}</div>
<div class='answers'>${answers.join('')}</div>
</div>
`
);
})
questionBlock.innerHTML = output;
}
build();

You need to call document.querySelector('.card') after calling build(). It cannot find HTML elements that do not exist yet.
const questionBlock = document.querySelector('.card-container');
function build() {
let output = [];
...some unimportant code here...
output.push(
`
<div class='card'>
<div class='question'>${current.question}</div>
<div class='answers'>${answers.join('')}</div>
</div>
`
);
})
questionBlock.innerHTML = output;
}
build();
const questionCard = document.querySelector('.card');

An alternative to the more correct answers is:
const questionCard = document.getElementsByClassName('card');
now: questionCard is a live HTMLCollection, and questionCard[0] will be the first element with class including card

Related

How to split html code from a page into nodes

I want to read the html from a site and then split it into nodes. I tried this code:
function load() {
$(document).ready(function () {
$.get("https://example.com/index.html", function (data) {
const loadpage = async function() {
var nodes = [...data.childNodes].slice(-3);
var cont = document.getElementById("container");
var msg = nodes;
});
if(cont.innerHTML='') {
cont.insertAdjacentHTML('afterbegin', msg);
} else {
cont.innerHTML=msg;
}
};
loadpage();
});
});
}
load();
html looks like this:
<main>
<div class="msg">something</div>
<div class="msg">something</div>
<div class="msg">something</div>
<div class="msg">something</div>
<div class="msg">something</div>
<div class="msg">something</div>
</main>
the expected output should be:
<div class="msg">something</div>
<div class="msg">something</div>
<div class="msg">something</div>
since I want only the last 3 nodes.
Thank you.
It is not necessary to use async await here and you are doing it wrong
Please read How to return values from async functions using async-await from function?
Your load is also wrong and too complex. You should not add a window event handler in a function and the test to insert after if cont is empty is not useful. Your test is also not a comparison (== '' or === '') but an assignment (= '').
Add the data to a partial element and slice the result
$(document).ready(function() {
const cont = document.getElementById("container");
$.get("https://example.com/index.html", function(data) {
const div = document.createElement('div')
div.innerHTML = data; // assuming HTML string?
[...div.querySelectorAll('.msg')]
.slice(-3)
.forEach(div => cont.innerHTML += div.outerHTML);
});
});

Is it okay to append a template element's content to DocumentFragment?

This code is working fine as expected.
index.html
<div id="sliderContent">
<div class="item" id="item-1">
<img src="images/image1.jpg">
</div>
</div>
<template id="sliderItem">
<div class="item">
<img src="dummy_image.jpg">
</div>
</template>
scripts.js
const next = document.querySelector("#next");
const sliderContent = document.querySelector("#sliderContent");
next.addEventListener('click', () => {
const sliderItem = document.querySelector("#sliderItem");
const moreImages = ['image2.jpg', 'image3.jpg', 'image4.jpg'];
// Create a DocumentFragment first
const moreImagesHTML = document.createDocumentFragment();
moreImages.forEach((item) => {
const sliderItemClone = sliderItem.content.cloneNode(true);
const sliderImage = sliderItemClone.querySelector('img');
sliderImage.src = `images/${item}`;
// Append each item to the DocumentFragment
moreImagesHTML.append(sliderItemClone);
});
// Finally append DocumentFragment to
sliderContent.append(moreImagesHTML);
I am not sure if this is valid and standard way in JS. I am appending the content of the template which is already a DocumentFragment to another DocumentFragment i.e. moreImagesHTML. Is Valid in JS?

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.

Accessing variables inside Eventlisteners - Vanilla JavaScript

I have 2 divs with same class but different textContent
I want to extracts its value using eventListners and pass it as a argument to another function
Html Code
<div class = "seasonDeatils__container">
<p class = "seasonYear ">2020</p>
</div>
<div class = "seasonDeatils__container">
<p class = "seasonYear ">2019</p>
</div>
JavaScript Code I tried
var season;
const getSeasonYear = document.querySelectorAll('.seasonDeatils__container');
getSeasonYear.forEach((el)=>{
el.addEventListener('click', ()=>{
season = el.firstElementChild.textContent;
})
})
//I now want to access the 'season' value elsewhere in the code
Just pass the value of season as an argument from inside your click listener function itself to a function elsewhere in your code as follows:
var season;
const getSeasonYear = document.querySelectorAll('.seasonDeatils__container');
getSeasonYear.forEach((el)=>{
el.addEventListener('click', ()=>{
season = el.firstElementChild.textContent;
someOtherFunction(season);
})
})
someOtherFunction = x => {
console.log(x);
alert(x);
}
<div class = "seasonDeatils__container">
<p class = "seasonYear ">2020</p>
</div>
<div class = "seasonDeatils__container">
<p class = "seasonYear ">2019</p>
</div>

Event listener isnot working in asynchronous js

I know why it shows error because due to asynchronous, button is not loaded yet. Is there any way to fix it? I cannot explain much in words. At the time window is loaded , there is no button because it appears only after clicking id. i tried to put all codes but stack overflow requires much explanation
This is my main js code. Fetch works and i didnot include all codes.
const controlMovie = async()=> {
const id = window.location.hash.replace('#', '');
if(id){
// new id
clearMovie();
state.control = new Control(id);
await state.control.getMovies();
UImovie(state.control);
}
return id;
};
const viewList = async()=>
{
const id = window.location.hash.replace('#', '');
state.view= new Control(id);
await state.view.getMovies();
UIlist(state.view);
}
['hashchange', 'load'].forEach(event => window.addEventListener(event, controlMovie));
document.querySelector('.add').addEventListener('click', viewList);
This is for UI js part
const UImovie = (info)=> {
const markup = `
<div class="img-fig">
<img src="${info.image}" alt="${info.title}" class="movie-img">
</div>
<div class="movie_details">
<br>
<h3 style="align-items: center; font-weight: bold;"> ${info.title}</h3>
<p>Writer: ${info.writer}</p>
<p>Released date: ${info.year}</p>
<p>Actors: ${info.actors} </p>
<p>imdbRating: ${info.rating}</p>
<p>Total seasons: ${info.seasons}</p>
<p style="font-style: italic; color: red; font-size: 16px;"> "${info.story}"</p>
<button class= "add">+ Add to watchlist</button>
</div>
</div>
`;
document.querySelector('.movies-result').insertAdjacentHTML('afterbegin', markup);
};
const UIlist = (UI)=> {
const markup = `
<h3> ${UI.title} <button class="icons"><ion-icon name="trash"></ion-icon></button></h3>
`;
document.querySelector('.lists').insertAdjacentHTML('afterbegin', markup);
}
As commented, based on the provided code, you are added .icons dynamically. but .addEventListener is being executed during pageload. Due to this, when its executed, there is no elements available on DOM and no listener is added.
You should try using HTMLElement objects instead:
const UIlist = (UI)=> {
const h3 = document.createElement('h3');
h3.innerText = UI.title;
const button = document.createElement('button');
const icon = document.createElement('ion-icon');
icon.setAttribute('name', 'trash');
button.append(icon);
button.classList.add('icons');
button.addEventListener('click', function() {
console.log('Button Clicked');
})
h3.append(button)
document.querySelector('.lists').insertAdjacentElement('afterbegin', h3);
}
UIlist( { title: 'Bla' } )
<div>
<div class='lists'></div>
</div>

Categories

Resources