javascript
ajax
class-properties
asynchronous
duplicate

javascript class property not set in success function of ajax call

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When a class property does not update inside an Ajax success callback, the cause is usually one of two things: the value of this changed, or the property is being read before the asynchronous request finished. Both problems are common because callbacks change execution context and timing at the same time.

The Two Problems to Check First

The failure usually comes from:

  • lost this binding inside the callback
  • assuming async work finished before it actually did

Those are different bugs. You need to know which one you have before fixing it.

Lost this in a Regular Callback

With an ordinary function expression, this inside the callback is not automatically the class instance.

javascript
1class UserStore {
2  constructor() {
3    this.userName = null;
4  }
5
6  load() {
7    $.ajax({
8      url: "/user",
9      success: function (data) {
10        this.userName = data.name;
11      }
12    });
13  }
14}

In that example, this.userName usually does not refer to the UserStore instance. Inside the callback, this is determined by how the function is called, not by where it was written.

Fix It with an Arrow Function

Arrow functions keep the surrounding lexical this, which is usually the cleanest fix in modern JavaScript.

javascript
1class UserStore {
2  constructor() {
3    this.userName = null;
4  }
5
6  load() {
7    $.ajax({
8      url: "/user",
9      success: (data) => {
10        this.userName = data.name;
11      }
12    });
13  }
14}

Now this inside success is the class instance because the arrow function closes over the this value from load.

Alternative Fix: Save a Reference or Use bind

If you cannot use arrow functions, the older patterns still work.

javascript
1class UserStore {
2  constructor() {
3    this.userName = null;
4  }
5
6  load() {
7    const self = this;
8
9    $.ajax({
10      url: "/user",
11      success: function (data) {
12        self.userName = data.name;
13      }
14    });
15  }
16}

Or:

javascript
success: function (data) {
  this.userName = data.name;
}.bind(this)

Both are valid, but arrow functions are usually easier to read.

Async Timing Still Matters

Even when this is correct, the property may still appear unset if you read it too early.

javascript
1class UserStore {
2  constructor() {
3    this.userName = null;
4  }
5
6  load() {
7    $.ajax({
8      url: "/user",
9      success: (data) => {
10        this.userName = data.name;
11      }
12    });
13
14    console.log(this.userName); // still null here
15  }
16}

The request has not completed yet when that console.log runs. The callback executes later.

Return a Promise Instead of Guessing About Timing

The most reliable design is to make the asynchronous nature explicit.

javascript
1class UserStore {
2  constructor() {
3    this.userName = null;
4  }
5
6  load() {
7    return $.ajax({
8      url: "/user"
9    }).then((data) => {
10      this.userName = data.name;
11      return data;
12    });
13  }
14}
15
16const store = new UserStore();
17store.load().then(() => {
18  console.log(store.userName);
19});

Now callers have a correct place to wait for completion.

Modern fetch Version

If you are not tied to jQuery, the same pattern is clearer with fetch.

javascript
1class UserStore {
2  constructor() {
3    this.userName = null;
4  }
5
6  async load() {
7    const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
8    const data = await response.json();
9    this.userName = data.name;
10    return data;
11  }
12}
13
14(async () => {
15  const store = new UserStore();
16  await store.load();
17  console.log(store.userName);
18})();

This avoids the callback-style context problem entirely and makes execution order much easier to reason about.

Debugging Checklist

When this bug appears, inspect three things immediately:

  1. Log this inside the callback.
  2. Log the property before and after the request resolves.
  3. Check whether the caller is reading the property synchronously.

Those three checks usually identify the problem in a minute or two.

Common Pitfalls

The biggest mistake is fixing the this binding but still reading the property before the request completes. That solves only half of the bug.

Another issue is using regular function callbacks out of habit inside class methods. In asynchronous code, that often loses the instance context.

A third problem is mutating state in callbacks without returning a promise or exposing a completion signal, which forces callers to guess about timing.

Summary

  • If a class property is not updated in an Ajax success callback, check both this binding and async timing.
  • Arrow functions are usually the cleanest way to preserve instance context.
  • 'bind(this) and const self = this also work when needed.'
  • Do not read the property synchronously after starting the request.
  • Return a promise or use async and await so callers can wait correctly.

Course illustration
Course illustration

All Rights Reserved.