Jleibham
Jleibham

Reputation: 530

Using an event listener inside a class method to call another class method returning undefined

I'm just learning how to use javascript classes. I'm having some difficulty understanding how to make event listeners call methods within a class. Specifically, whenever I call the this.infoBoxActive on click, all my variables in the method return undefined.

What I eventually want to do is have a toggle method that onclick switches between true and false and then calls either infoBoxActive or infoBoxDective based on its state. I've been playing around with my code most of the day trying various things but I seem to be sparking the same issue of my variables going undefined. If I call the method direct my everything works great.

I've been using a promise to gather my data from a local JSON file, but I wasn't sure how to return the Object in my resolve so right now I'm calling all my new classes from the promise. I don't know if this would be part of the problem.

I've tried reading some posts of similarity, but either I wasn't able to understand the solution or it wasn't pertaining to my exact problem, so I apologize if this is a duplicate.

class EpisodeInfoBox extends Episode {
  constructor({ title, date, description, tracklist } = {}) {
    super({ title, date, description, tracklist })

    this.titleContainer = document.querySelector('.episode-title');
    this.dateContainer = document.querySelector('.episode-date');
    this.descriptionContainer = document.querySelector('.episode-description');
    this.tracklistContainer = document.querySelector('.episode-tracklist');

    this.infoBoxButton = document.getElementById('infoBoxButton');

    this.infoBoxButton.addEventListener('click', this.infoBoxActive);
  }



  infoBoxActive(){
    this.titleContainer.innerHTML = this.title;
    this.dateContainer.innerHTMLs = this.date;
    this.descriptionContainer.innerHTML = this.description;

    // Creates list-items for track list
    let tracklistHTML = '';
    for (let i = 0; i < this.tracklist.length; i++) {
      tracklistHTML += `<li>${this.tracklist[i].song} - ${this.tracklist[i].artist}</li>`;
    }
    this.tracklistContainer.innerHTML = tracklistHTML;
  }
}

my promise

export default function service(url) {
  return new Promise(function(res, rej) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.onreadystatechange = handleResponse;
    xhr.onerror = function(error) {
      rej(error)
    }
    xhr.send();

    function handleResponse() {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          var resObject = JSON.parse(xhr.responseText);
          res(resObject)
        } else {
          rej(this.statusText)
        }
      }
    };
  });
}

My resolve

function callService(){
  service('/data/episodes.json')
    .then(retrieveEpisode)
    .then(makeEpisode)
    .catch(function(e) {
      console.log(e)
    });
}

function retrieveEpisode(episodeArray) {
  return episodeArray[0];

}

function makeEpisode(episode){
  let newEpisode = new Episode(episode);
    newEpisode.setEpisodeImage();
  let newAudioPlayer = new AudioPlayer(episode);
  let newEpisodeInfoBox = new EpisodeInfoBox(episode);
}

Upvotes: 0

Views: 1899

Answers (1)

jfriend00
jfriend00

Reputation: 707158

Change this:

 this.infoBoxButton.addEventListener('click', this.infoBoxActive);

to this:

this.infoBoxButton.addEventListener('click', this.infoBoxActive.bind(this));

When an event listener is called, it will not have your object's this pointer set so infoBoxActive() is called with an inappropriate value of this and thus you don't see the properties you expect. You can use .bind() as shown above to reattach the appropriate this value before calling your method.


In Javascript, when you pass this.infoBoxActive as an argument to a function, a reference to the .infoBoxActive method is passed, but there is no connection at all to this. It's just a reference to a function. So, the listener then calls that function and sets its own value for this which will not be your object. Using .bind() you can create a function stub that will set the value of this for you when calling your function.

Upvotes: 2

Related Questions