2

I have an issue using XMLHttpRequest with typescript, here is a typescript class:

class Myclass {
 constructor() {
   this.init();
 }

 private init() {
  const req = new XMLHttpRequest();
  req.onreadystatechange = ( event: Event ): any => {
   if (this.readyState === XMLHttpRequest.DONE) {
    if (this.status === 200) {
      this.render(this.responseText)
    }
   }
  };

  req.open('GET', '/api/test', true);
  req.send(null);
 };

private render( data:any ) {
  console.log(`use ${data}`)
 }
}

in this case 'this' will refer to the typescript class Myclass and using a javascript function 'this' will refers to the request and i will not be able to call my class method render().

how can i call my render() method and still have access to the response ?

arkaii
  • 23
  • 1
  • 3
  • In a given context, `this` has only one value. It can't refer both to the request _and_ to the class. Since you use double arrows function, the class context is passed, so `this` refers to the class and `this.readyState` is likely undefined. – Jeremy Thille Jul 25 '17 at 09:32
  • If this was a plain JS question I'd put this down as "Yet another inappropriate use of an arrow function" question, but I don't know if the TypeScript makes a difference there. – Quentin Jul 25 '17 at 09:34

1 Answers1

0

You can already access the XMLHttpRequest using the req variable.

If you prefer a more clean way, you can bind the request to your callback function lite so:

req.onreadystatechange = (function ( request: XMLHttpRequest, event: Event ): any {
    if (request.readyState === XMLHttpRequest.DONE) {
        if (request.status === 200) {
            this.render(request.responseText)
        }
    }
}).bind(this, req);

or use the other way round:

req.onreadystatechange = (function ( myClassObject: MyClass, event: Event ): any {
    if (this.readyState === XMLHttpRequest.DONE) {
        if (this.status === 200) {
            myClassObject.render(this.responseText)
        }
    }
}).bind(req, this);

With the bind function you can assign a fixed this object to a function as well as parts or all of its parameters.

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

Bellian
  • 2,009
  • 14
  • 20
  • No, don't use `bind` at all. Arrow functions for closing over `this` and `req` are the cleanest you get. – Bergi Jul 25 '17 at 10:09
  • This general ban of `bind` might be true in pure ES6 enviorments but not in mixed or prue ES5 enviorments. – Bellian Jul 25 '17 at 10:21
  • Sure, but even then it's a bad idea to also bind `req`, especially with mixing up the order. Also the OP already uses arrow functions just fine (with a transpiler or not, it doesn't matter). – Bergi Jul 25 '17 at 10:25
  • There is no order swapping but a scope swapping. This might be handy in some cases. In this minimal example it might be unnecessary to bind `req`, but consider creating multiple requests in a loop (without let.. there is no good transpile method..). The binding would come in handy. – Bellian Jul 25 '17 at 10:33