Mickey Vershbow
Mickey Vershbow

Reputation: 307

Javascript - AJAX Class Method cannot invoke other class methods from within the 'Success' function?

I have two classes: "Company" and "Employees".

I've created all the "Company" objects already, and now I want to create all the "Employee" objects. Since I need to make an Ajax call to get the employee data, and then associate each employee with the company they work for, my approach is as follows:

  1. Create a Company class method that makes the Ajax call getEmployeeData. This will run as a click event listener attached to each company box, so a user will see the company's employees when they click on the company box.
  2. From the Ajax call 'success' method, call another class method populateEmployees(ajaxResult), passing in the data from our API call.
  3. As employee objects are instantiated, they will be added to the associated company's list of employees this.employees = [];. That's why we're doing all this as class methods in the Company class.

Ok -- now for some reason, when I try to execute step #2, it fails and says this.populateEmployees is not a function. My first thought was that it must be a scoping issue, that the 'success' method in the ajax call couldn't access the other class methods...but that doesn't make any sense since i'm using lexical scoping. What's more, I've used this pattern several times before and it's always worked. I'm even looking at other examples of this in my code for other projects, and it all works, so I can't figure out why I'm getting this error now. See below for code (simplified for brevity)

class Employee {
  constructor(employeeOptions) {
    this.name = employeeOptions.name;
    this.company = employeeOptions.company;
  }
}

class Company {
  constructor(companyOptions) {
    this.companyName = companyOptions.companyName;
    this.employees = [];
    this.newCompanyBoxElement = document.createElement("div");
  }
  attachEventListeners(){
    this.newCompanyBoxElement.addEventListener("click", 
    this.getEmployeeData);
  }
  getEmployeeData() {
    //send the request to the server and process the results
    $.LoadingOverlay("show");
    $.ajax({
      type: "GET",
      url: getURL,
      dataType: "JSON",
      data: {
        sessionToken: sessionToken,
        subjectId: subjectId,
        resolveType: false,
      },

      // process the returned result of the Ajax call
      success: (ajaxResult) => {
        // Call function to populate triggered filter boxes
        // !! this is where things break
        this.populateEmployees(ajaxResult);
      },
      complete: () => {
        // Hide loading overlay
        $.LoadingOverlay("hide");
      },
      //handle failure
      error: (error) => {
        console.log(error);
      },
    });
  }

  // Function to populate employee objects, invoked by the API call above
  populateEmployees(ajaxResult) {
    // instantiate objects
    console.log("populate employees function");

    for (let item of ajaxResult) {
      let newEmployee = new Employee({
        name: item.name,
        company: this.companyName,
      });
      // Add employee to array of employees associated with company
      this.employees.push(newEmployee);
    }
  }
}


Upvotes: 2

Views: 538

Answers (1)

Mickey Vershbow
Mickey Vershbow

Reputation: 307

This was a scoping issue, as @wahwahwah pointed out. I needed to add a fat arrow to the event listener definition in order to give it lexical scope:

Old code:

attachEventListeners(){
    this.newCompanyBoxElement.addEventListener("click", 
    this.getEmployeeData);
  }

New (working) code:

  attachEventListener() {
    this.newFilterGroupBox.addEventListener("click", () => {
      this.getEmployeeData();
    });

Upvotes: 1

Related Questions