0

I have an object x of class C. The attribute x.myval should be set by calling x.load(), which in turn should get its data from an asynchronous ajax call.

class C {
    constructor() {
        this.myval = "hello";
    }
    load() {
        return $.ajax({
            type: "GET",
            url: "file.txt",
            // suppress "xml not well-formed error in firefox", 
            beforeSend: function(xhr){
                if (xhr.overrideMimeType) { xhr.overrideMimeType("text/plain"); }
            },
            contentType: "text/plain",
            dataType: "text",
            success: function(text) {
                this.myval = text;
            }
        });
    }
}

var x = new C();
$.when(x.load()).done(function(a1,a2) {
    console.log(x.text); //should print the content of file.txt
});

I get an error this.myval is undefined, obviously because this is set to this of jquery-$.

I also tried:

class C {
    constructor() {
        this.myval = "hello";
    }
    load() {
        var callback = function callbackClosure(mythis) {return function(text) {
            this.myval = text;
        }}(this);

        return $.ajax({
            type: "GET",
            url: "file.txt",
            // suppress "xml not well-formed error in firefox", 
            beforeSend: function(xhr){
                if (xhr.overrideMimeType) { xhr.overrideMimeType("text/plain"); }
            },
            contentType: "text/plain",
            dataType: "text",
            success: callback
        });
    }
}

var x = new C();
$.when(x.load()).done(function(a1,a2) {
    console.log(x.text); //should print the content of file.txt
});

But this trew an exception jQuery.Deferred exception: assignment to undeclared variable...

Markus
  • 578
  • 6
  • 26

1 Answers1

1

this doesn't refer to your instance in this line:

success: function(text) {
    this.myval = text;
}

You can make a temp variable referring to your instance in the outer method, like this:

load() {
    var that = this;
    return $.ajax({
        type: "GET",
        url: "file.txt",
        // suppress "xml not well-formed error in firefox", 
        beforeSend: function(xhr){
            if (xhr.overrideMimeType) { xhr.overrideMimeType("text/plain"); }
        },
        contentType: "text/plain",
        dataType: "text",
        success: function(text) {
            that.myval = text;
        }
    });
}

Or, you can use an arrow function:

load() {
    return $.ajax({
        type: "GET",
        url: "file.txt",
        // suppress "xml not well-formed error in firefox", 
        beforeSend: function(xhr){
            if (xhr.overrideMimeType) { xhr.overrideMimeType("text/plain"); }
        },
        contentType: "text/plain",
        dataType: "text",
        success: (text) => {
            this.myval = text;
        }
    });
}
Phiter
  • 14,570
  • 14
  • 50
  • 84
  • They don't *have* to... there are more elegant solutions. Also, in the future if there's a duplicate (canonical) could you also vote to close as well instead of answering right away? This is an incredibly common problem. – Andrew Li Aug 20 '18 at 12:52
  • Yeah, I rephrased that. Arrow function is the way to go. – Phiter Aug 20 '18 at 12:52
  • @Li357 it is indeed extremely common. I had answered the exact same thing about an hour before this one https://stackoverflow.com/questions/51929737. But it is hard to mark this as a duplicate of another question. I couldn't find any question that would fit. – Phiter Aug 20 '18 at 13:39
  • Then don't keep answering. Vote to close as duplicates. – Andrew Li Aug 20 '18 at 13:40
  • @Li357 think of noobs like me: I'm glad I got an answer. I have been searching for more than an hour before I posted this question. – Markus Aug 20 '18 at 17:54
  • @Markus Good to hear, and I'm not saying your question is bad. Dynamic this binding is really tricky and takes a lot getting used to. I'm just telling Phiter to, in the future, close as a duplicate (which is not an inherently bad thing) since the duplicate goes a lot more in depth. – Andrew Li Aug 20 '18 at 18:12