1

With JavaScript, when creating a class, while instantiating that class, I want to populate a public property. I can do this using a setter, however, the value I want comes from an external website which I retrieve via an ajax get call. The issue becomes that the new class object does not have the appropriate property value when I create it. Here's some sample code:

class MyTestClass {
  constructor() {
    this._ipaddress = "";
  }
  get ip() {
    return this._ipaddress;
  }
  set ip(value) {
    createIpAddr();
  }
  createIpAddr() {
    var myIpAddr = "";
    var strUrl = "https://api.ipify.org/?format=json";
    $.ajax({
      url: strUrl,
      success: function(data) {
        this._ip = data.ip;
      },
      //async:false //Performing this in sync mode to make sure I get an IP before the rest of the page loads.
    });
    return myIpAddr;
  }
}

var testobj = new MyTestClass();
console.log(testobj.ip);

The problem here is that I can't be sure the IP will be populated in time to use after creating the new instance of the class. I've tried promises and deffered, but they have the same problem, I can't populate the variable before I need it. I'm trying to adjust the way I am looking at this and adding callbacks, but the issue is that I need the correct value in the class before I can use the class for the next call, where I am passing this object to it.

Is there a simple solution I am over looking? I have been through a million of these threads about async: false, and I don't want to start a new one, but what is a better choice in this case?

I want to set a class property from an ajax response when instantiating the class object.

4
  • _ip vs _ipaddress? Commented Feb 20, 2019 at 20:56
  • Have a look at this question. Don't make the ajax request within the class, make it before instantiating the class. And yes, that means that you will need to change the code that creates the class, but you need to do that anyway - you cannot do this synchronously. Commented Feb 20, 2019 at 20:58
  • Here's one way: jsfiddle.net/khrismuc/6ogLaujp Commented Feb 20, 2019 at 21:07
  • this and this are both relevant. Commented Feb 20, 2019 at 21:30

1 Answer 1

1

You could have your constructor return an async IIFE, allowing you to then await the creation of a new class instance.

That would look something like this:

class MyTestClassAsync {
  constructor() {
    return (async() => {
      this._ip = (await this.createIpAddrAsync()).ip;
      return this;
    })();
  }
  get ip() {
    return this._ip;
  }
  set ip(value) {
    this._ip = value;
  }
  createIpAddrAsync = () => $.get("https://api.ipify.org/?format=json");
}

async function Main() {
  var testobj = await new MyTestClassAsync();
  console.log(testobj.ip);
}

Main();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

I've made the personal decision to append "Async" to the method and class names, just so that it's clear they need to be awaited.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.