/    Sign up×
Community /Pin to ProfileBookmark

JS not working on dynamically loaded content

Short and sweet, I have this on a page and it works.

WHen the page is loaded via fetch it doesn’t do anything.

How can I adjust it so it works in this way?

[code]
document.querySelectorAll(“.drop-zone__input”).forEach(inputElement =>{

var dropZoneElement = inputElement.closest(“.drop-zone”);

dropZoneElement.addEventListener(“click”, e =>{
inputElement.click();
})

inputElement.addEventListener(“change”, e=>{
if (inputElement.files.length){
updateThumbnail(dropZoneElement, inputElement.files[0])
}

dropZoneElement.classList.remove(“drop-zone–over”);
})

dropZoneElement.addEventListener(“dragover”, e=>{
e.preventDefault();
dropZoneElement.classList.add(“drop-zone–over”);
})

var dropZoneElement = inputElement.closest(“.drop-zone”);

[“dragleave”, “dragend”].forEach(type =>{
dropZoneElement.addEventListener(type, e =>{
dropZoneElement.classList.remove(“drop-zone–over”);
})
})

dropZoneElement.addEventListener(“drop”, e =>{

e.preventDefault();
if (e.dataTransfer.files[0].type.startsWith(“image/”)) {

/* Is a Image */
if (e.dataTransfer.files.length){
inputElement.files = e.dataTransfer.files;
updateThumbnail(dropZoneElement, e.dataTransfer.files[0]);
}
dropZoneElement.classList.remove(“drop-zone–over”);

} else {
/* Not a Image */
dropZoneElement.querySelector(“.drop-zone__prompt”).innerHTML = “Not a image file”;
}

})

})

function updateThumbnail(dropZoneElement, file){

let thumbnailElement = dropZoneElement.querySelector(“.drop-zone__thumb”);

if (dropZoneElement.querySelector(“.drop-zone__prompt”)){
dropZoneElement.querySelector(“.drop-zone__prompt”).remove;
}

if (!thumbnailElement){
thumbnailElement = document.createElement(“div”);
thumbnailElement.classList.add(“drop-zone__thumb”);
dropZoneElement.appendChild(thumbnailElement);
}

thumbnailElement.dataset.label = file.name;

const reader = new FileReader;
reader.readAsDataURL(file);
reader.onload = () =>{
thumbnailElement.style.backgroundImage = `url(‘${ reader.result }’)`;
}

}

[/code]

to post a comment
JavaScript

7 Comments(s)

Copy linkTweet thisAlerts:
@daveyerwinNov 11.2021 — @kiwis#1639263

can you show us the code

that does the "fetching" please
Copy linkTweet thisAlerts:
@kiwisauthorNov 11.2021 — @DaveyErwin#1639280

Sure, it's part of a bigger JS file. It's loaded a page into a parent element on my main page?
<i>
</i>async function addPlayer(txt =''){
showLoader();
fetch('pages/player-add.php')
.then(function(response){
return response.text();
})
.then(function(html){
bodyContent.innerHTML = txt + html
hideLoader();
})
.catch(function(error){
bodyContent.innerHTML = '&lt;p style="color:red;"&gt;' + error + '&lt;/p&gt;';
hideLoader();
});
}
Copy linkTweet thisAlerts:
@daveyerwinNov 11.2021 — Okay, I assume ...

pages/player-add.php is the file from your first post

and

this line ...

bodyContent.innerHTML = txt + html

is adding the content of pages/player-add.php

to the body of the current page

did I assume correctly ?

if that is the case then the javascript is considered

as plain text and will not execute



Copy linkTweet thisAlerts:
@kiwisauthorNov 11.2021 — @DaveyErwin#1639294

Yes, however I've also tried to place the original code above in my main index.php page where it's called.

How can I get my JS to work then, assume it needs to be placed on my index page but needs to listen for events which are loaded dynamically .
Copy linkTweet thisAlerts:
@daveyerwinNov 11.2021 — > @kiwis#1639263 I have this on a page and it works.



is it at the end of the page, after the body has loaded ?

or is it called by onload ?

as an aside ...

I feel confidant that this will work ...

create a script element and set it's source to the url of the script

then call the function if necessary

also ...

if you will always consider innerHTML as "read only"

you will avoid some hard to diagnose bugs

instead, create elements or textNodes then

set their properties and content
Copy linkTweet thisAlerts:
@SempervivumNov 12.2021 — @kiwis#1639263 A sophisticated way to fix this issue is taking advantage of event bubbling: Add an event listener to body and check if event.target is the required one:
``<i>
</i> document.addEventListener("click", e =&gt;{
if event.target.classList.contains('drop-zone') {
dropzoneElement = event.target;
inputElement = dropzoneElement.querySelector('.drop-zone__input')
inputElement.click();
}
})<i>
</i>
`</CODE>
(not tested)<br/>
However, as visible from this snippet, the code would grow a bit complex as you are needing both, <C>
dropzoneElement</C> and <C>inputElement</C>. Therefore I do not recommend to go this way but use a different procedure:<br/>
Place the javascript for adding the eventlisteners inside a function and call it after the content has been loaded:
<CODE>
`<i>
</i> function addListeners() {
document.querySelectorAll(".drop-zone__input").forEach(inputElement =&gt; {

var dropZoneElement = inputElement.closest(".drop-zone");

dropZoneElement.addEventListener("click", e =&gt; {
inputElement.click();
})

inputElement.addEventListener("change", e =&gt; {
if (inputElement.files.length) {
updateThumbnail(dropZoneElement, inputElement.files[0])
}

dropZoneElement.classList.remove("drop-zone--over");
})

dropZoneElement.addEventListener("dragover", e =&gt; {
e.preventDefault();
dropZoneElement.classList.add("drop-zone--over");
})

var dropZoneElement = inputElement.closest(".drop-zone");

["dragleave", "dragend"].forEach(type =&gt; {
dropZoneElement.addEventListener(type, e =&gt; {
dropZoneElement.classList.remove("drop-zone--over");
})
})


dropZoneElement.addEventListener("drop", e =&gt; {


e.preventDefault();
if (e.dataTransfer.files[0].type.startsWith("image/")) {

/* Is a Image */
if (e.dataTransfer.files.length) {
inputElement.files = e.dataTransfer.files;
updateThumbnail(dropZoneElement, e.dataTransfer.files[0]);
}
dropZoneElement.classList.remove("drop-zone--over");

} else {
/* Not a Image */
dropZoneElement.querySelector(".drop-zone__prompt").innerHTML = "Not a image file";
}

})

})
}<i>
</i>
`</CODE>
(function updateThumbnail remains unchanged)<br/>
Then call this function after the dropzone has been loaded:
<CODE>
`<i>
</i>async function addPlayer(txt =''){
showLoader();
fetch('pages/player-add.php')
.then(function(response){
return response.text();
})
.then(function(html){
bodyContent.innerHTML = txt + html;
addListeners();
hideLoader();
})
.catch(function(error){
bodyContent.innerHTML = '&lt;p style="color:red;"&gt;' + error + '&lt;/p&gt;';
hideLoader();
});
}<i>
</i>
``

(not tested)
Copy linkTweet thisAlerts:
@kiwisauthorNov 12.2021 — Such an easy solution. Wrap your code in a function and only call it once loaded.

I've tested it and it seems to work.
×

Success!

Help @kiwis spread the word by sharing this article on Twitter...

Tweet This
Sign in
Forgot password?
Sign in with TwitchSign in with GithubCreate Account
about: ({
version: 0.1.9 BETA 5.7,
whats_new: community page,
up_next: more Davinci•003 tasks,
coming_soon: events calendar,
social: @webDeveloperHQ
});

legal: ({
terms: of use,
privacy: policy
});
changelog: (
version: 0.1.9,
notes: added community page

version: 0.1.8,
notes: added Davinci•003

version: 0.1.7,
notes: upvote answers to bounties

version: 0.1.6,
notes: article editor refresh
)...
recent_tips: (
tipper: @AriseFacilitySolutions09,
tipped: article
amount: 1000 SATS,

tipper: @Yussuf4331,
tipped: article
amount: 1000 SATS,

tipper: @darkwebsites540,
tipped: article
amount: 10 SATS,
)...