Setting instance variables in constructor and observables - "this" is unknown

Hi everyone :slight_smile: ,

Hopefully this is a noob question about promises/observables and instance variables…

Having difficulties in a constructor that opens an XML file (via http get), parses it to JSON and trying to save the resulting JSON for later use. All usages of xml2js I see merely log the result of the xml2js and doesn’t really do anything with it.

export class Election {
public xml: string = “”;
public jsonObj: string = “”;
public BallotItems: BallotItem[];
public Contests: Contest[];
public myhttp: Http;

public edfFile: string;

//take a filename, parse it to json, then build subordinate objects (Contests, BallotItems, etc.)
constructor(_http: Http, aString: string) {
    this.myhttp = _http;
    if (null != aString) {
        this.edfFile = aString;

        try {

            let jsonData;
            let xmlData;
            this.myhttp.get(this.edfFile).map(res => res.text()).subscribe(data => {
                this.xml = data.toString();   //  <<<<<<<<<  doesn't throw an error, but doesn't persist,either
                xmlData = data.toString();
                parseString(xmlData, function (err, jsonData) {
                    this.jsonObj = jsonData;  //<<<<<<<  "this" is unknown at this point
                    this.setContests();   //<<<<<<<<<<<  "this" is unknown at this point
                    // this.getBallotItems(); //<<<<<<<<   "this" is unknown at this point
                });
            });


        } catch (e) {
            console.log("Error:", e);
        }
    }
}

I’m getting the XML and I see the JSON parsed from it, but I can’t save the JSON.

My goal is to save the result of the JSON from parseString to the instance variable jsonObj (i.e. this.jsonObj) so I can query it later and create other objects based on certain parts of the JSON.

I’m getting a runtime error:
TypeError: Cannot set property ‘jsonObj’ of undefined

I’m assuming it’s because the object itself hasn’t been defined because it’s in the constructor.

I’m rather new to Observables, Promises, etc… I’m coming from a Java background where you process something and it happens immediately (i.e. not something to be eventually processed and returned later maybe), so I’m having a hard time figuring out when my variables get populated so I can use them. :frowning:

Thanks for your insights,

Bret

Wait! I just saw an example where the author saved off “this” before diving into the Observable code:

 try {
            var self = this;

            let jsonData;
            let xmlData;
            this.myhttp.get(this.edfFile).map(res => res.text()).subscribe(data => {
                self.xml = data.toString();

                console.log("XML is: " + this.xml);
                xmlData = data.toString();
                //                    console.log("in GET, json is: " + data);

                // xml to json
                //var parser = new Parser();
                parseString(xmlData, function (err, jsonData) {

                    console.log("jsonObj is : " + JSON.stringify(jsonData));
                    self.jsonObj = jsonData;
                    //                        console.log("jsonObj is " + this.jsonObj.toString());
                    self.setContests();
                    //                    this.getBallotItems();
                });
            });


        } catch (e) {
            console.log("Error:", e);
        }

Seems to work better… is this the “best practice” in Typescript/Angular/Ionic?

Thanks,

Bret

No. That code looks as though it was written years ago.

  1. You almost certainly want to use Angular’s HttpClient, not whatever http service you’re using.
  2. Use let, not var. (eg let x = 5;)
  3. Look at the code examples for HttpClient here: https://angular.io/guide/http You can do in just a few lines what you are trying to do now with lots more.
  4. Personal rant: Using self = this is an admission of defeat.

You’re close, but there’s a better way.

Instead of using function (which you should pretty much never type in Ionic), you’d use the fat arrows syntax =>.

So instead of function (err, jsonData) { ... } you’d do (err, jsonData) => { ... }.

This will automagically manage this, so that you don’t have to do the let self = this; stuff.

Thanks so much, SigmundFroyd! Thanks for the lesson and helping out! :slight_smile: Thank you, too, AaronSterling :slight_smile: .

That’s the problem with the documentation available when you’re chasing something that changes as fast as Ionic… a lot of the documentation is for something 1 or 2 revs back and all the examples are out of date. I really appreciate you guys jumping in to help a noob.

Regards

Bret

1 Like