I’m trying to grab an element from page and add an addEventHandler to it. Element (link with class .catalog__link) was dynamically created in another external function when the page was loaded using insertAdjacentHTML. I invoke them both in third js file via import keyword. Everything loads perfectly on the page, the elements are created for me, but I can’t grab them from another function connected to the page. Here’s examples of codes. I have two external function, combined in one js file and simple html page
This is fillCatalog.js (First file)
const row = document.querySelector('.catalog__row');
export const fill = function (brand) {
fetch(`./data/${brand}.json`)
.then(function (response) {
return response.json();
})
.then(function (data) {
let products = [...data.products];
products.forEach(product => {
row.insertAdjacentHTML(
'afterbegin',
` <a class="catalog__link" href="#" >
<div class="catalog__product">
<div class="catalog__product-img">
<img class="catalog__productImg" src=${product['img-src']} alt="" srcset="" />
</div>
<h3 class="catalog__product-model">${product['model']}</h3>
<p class="catalog__product-brand">${product['brand']}</p>
<span class="catalog__product-price">${product['price']}</span>
</div></a>`
);
});
});
};
This is productSave.js (Second file)
class Product {
constructor(cardImg, cardName, cardBrand = '', cardPrice) {
this.cardImg = cardImg;
this.cardName = cardName;
this.cardBrand = cardBrand;
this.cardPrice = cardPrice;
}
}
const links = document.querySelectorAll('.catalog__link');
export const productSave = function () {
window.addEventListener('DOMContentLoaded', () => {
console.log(links);
links.forEach(link => {
link.addEventListener('click', e => {
productItem = link.querySelector('.catalog__product');
const newProduct = new Product(
productItem.querySelector('catalog__productImg').src,
productItem.querySelector('.catalog__product-model').textContent,
productItem.querySelector('.catalog__product-brand').textContent,
productItem
.querySelector('.catalog__product-price-price')
.textContent.replace(/D/g, '')
);
localStorage.setItem('newCard', JSON.stringify(newProduct));
console.log(card.querySelector('.card__name').textContent);
});
});
});
};
This is third file where I invoke external function
loadContent.js
import { fill } from './fillCatalog.js';
import { productSave } from './productSave.js';
fill('jordans');
productSave();
Simple HTML
<html lang="ru">
<head>
<!--=include head.html-->
</style>
</head>
<body>
<div class="catalog">
<div class="catalog__content">
<div class="catalog__row"></div>
</div>
</div>
</body>
<script type="module" src="../js/goodscart.js"></script>
<script type="module" src="../js/loadContent.js"></script>
</html>
I’ve tried use beforeend afterent and etc. Tried also use getElementsByTag, it returns empty HtmlCollection[]. After insertAdjacentHTML, can’t select like usually this links.
Could anyone help me please with this issue? I can’t find solution for that. Thank you
3
Answers
Thank you very much,Vincent. You gave me good direction to search solution.
i put it all to setTimeout. And it's working good. I'm not strong enough in JS to use and manipulate promises. Thank you
You need to define
links
inside the function to avoid it being initialized before the elements are rendered.Initialization of
links
Handling the
fill
PromiseFuthermore there is a fetch reuqest inside
fill
which returned a promise.Then you can properly chain the call to the following function like so
Workaround to detect classes in dom
You can also implement a detector that waits for at least one link to be rendered. This
Promise
would resolve after at least1
item withcatalog__link
can be found. Then you can chain your logic with.then(...)
. This one also includes a timeout of 10 seconds which executes.catch(...)
(if present otherwise throws) if the element was not found in time.fill
is an async process due to thefetch
but you’re callingproductSave
immediately after calling it so the DOM hasn’t been built by the time the code tries to pick up the elements.Move your links caching within the
productSave
function.It maybe easier to separate out the asynchronous parts from the synchronous parts. In this example there’s a separate
getData
function which is awaited and then the data can be filled, and saved.