How can I run javascript file after dom manipulation made in another js file?

500 views Asked by At

When I run my rails application and enter likeButton into the console it gives me Uncaught ReferenceError: likeButton is not defined at :1:1 (anonymous) @ VM1591:1 I tried moving the script in html to head and body. I am currently trying to use DOMContentLoaded but it seems I'm missing something. My overall goal is to change the color of the button once pressed and also keep the color after page refresh. I am using sessionStorage for this process. I just want to make sure that likeButton variable is declared after html is loaded. If its possible to done in javascript only.

//first js file
const BASE_URL = "http://localhost:3000"
const GPUS_URL = `${BASE_URL}/gpus`
const USERS_URL = `${BASE_URL}/users`

const gpuCollection = document.querySelector('#gpu-collection')

let wish = sessionStorage.getItem('wish');

class Gpu {
    constructor(gpuAttributes) {
        this.title = gpuAttributes.title;
        this.price = gpuAttributes.price;
        this.features = gpuAttributes.features;
        this.link = gpuAttributes.link;
        this.image = gpuAttributes.image;
        this.id = gpuAttributes.id;

    }

    render() {
        let div = document.createElement('div');
        div.classList.add('card');

        let h = document.createElement('h2');
        let t = document.createTextNode(`${this.title} ($${this.price})`);
        h.appendChild(t);
        div.appendChild(h);

        let h1 = document.createElement('h1');
        h1.classList.add('gpu-cat');
        h1.innerHTML = `${this.features}`;
        div.appendChild(h1);

        let button = document.createElement('button');
        button.classList.add('list_btn');
        button.innerHTML = '♡';
        div.appendChild(button);
        
        let a = document.createElement('a');
        let img = document.createElement('img');
        a.href = `${this.link}`;
        a.target = '_blank';
        img.src = `${this.image}`;
        img.classList.add('gpu-image');
        a.appendChild(img);
        div.appendChild(a);
        gpuCollection.appendChild(div);
    }

}
//second js file
document.addEventListener("DOMContentLoaded", function (){

let likeButton;

SignUp();
logInUser();
logOutUser();

function putGpusOnDom(gpuArray){
     gpuArray.forEach(gpu => {
       let newGpu = new Gpu(gpu)
        newGpu.render()
      }); 
         likeButton = document.querySelector("button"); 

                }  

function fetchGpus(){
            fetch(GPUS_URL)
            .then(res => res.json())
            .then(gpus => putGpusOnDom(gpus))
    }

const enableWish = () => {
            
            console.log(likeButton)
            sessionStorage.setItem('wish', 'red')
         }

 gpuCollection.addEventListener('click', function (){
            wish = sessionStorage.getItem('wish');
   
            if(wish !== 'red'){
                enableWish();
            }else{
                disableWish();
            }
        });

})
//html file
...
 <body>
<div id = "gpu-collection"></div>
    
<script type="text/javascript" src="src/Gpu.js"></script>
    <script type="text/javascript" src="src/index.js" ></script>
  </body>
</html>
1

There are 1 answers

1
Jon P On

As I mentioned in a comment the like button is not available on DOMContentLoaded if it is added dynamically. You need to wait until the button has been placed in the DOM

Use something like the following, I'm making some guesses here as there are some gaps in your code

document.addEventListener("DOMContentLoaded", function (){

//document.querySelector("button"); not yet available
//NOTE: The likeButton variable will ONLY be in scope INSIDE the event listener function
//      You will not be able to access directly in the console.
let likeButton;

SignUp();
logInUser();
logOutUser();

function putGpusOnDom(gpuArray){
     gpuArray.forEach(gpu => {
       let newGpu = new Gpu(gpu)
        newGpu.render()
      });
      //Now you have rendered the button it is available
      //CAUTION: querySelector("button") will grab the first button on the page 
      //         and ONLY the first button
      likeButton = document.querySelector("button");    
      //Log like button to console while it is still in scope.
      console.log(likeButton);
}  

function fetchGpus(){
            fetch(GPUS_URL)
            .then(res => res.json())
            .then(gpus => putGpusOnDom(gpus))
    }

const enableWish = () => {
            
            console.log(likeButton)
            sessionStorage.setItem('wish', 'red')
         }

})