0

I'm somewhat new to JS programming, so forgive me if this is simple... But I have created a class with various methods and properties. However, this code must run on IE11, so I used Babel to target that and convert the code. I'm not familiar with the syntax it's using, which could be part of the problem. My issue is that the loadLocationChildren method cannot call the _addLocations method. The browser gives me an error saying "this._addLocations is not a function." The output file from Babel is as follows:

"use strict";
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }


var LocationDataManager = function () {

    const isBusyChanged = "ISBUSYCHANGED";
    const selectedLocationChanged = "SELECTEDLOCATIONCHANGED";

    function LocationDataManager() {
        _classCallCheck(this, LocationDataManager);

        this._locationData = {};
        this._selectedLocation = null;
        this._loadHierachyUrl = "";
        this._loadLocationUrl = "";
        this._loadChildrenUrl = "";
        this._isBusy = 0;
        this._errorHandlerFunc = null;
    }

    _createClass(LocationDataManager, [{
        key: "location",
        value: function location(locationId) {
            return this._locationData[locationId];
        }
    }, {
        key: "selectLocation",
        value: function selectLocation(locationId) {
            var f = this._locationData[locationId];
            if (f === undefined || f === null) throw Error("Location does not exist.");else this.selectedLocation = f;
        }
    }, {
        key: "loadLocation",
        value: function loadLocation(locationId) {

            if (isNullOrEmpty(locationId)) return null;
            if (isNullOrEmpty(this._loadLocationUrl)) return null;

            var found = this._locationData[locationId];
            if (found != null) return found;

            this.isBusy = true;

            $.post(this._loadLocationUrl, {
                id: locationId
            }, function (data) {

                this._addLocations(data);
                this.isBusy = false;
                return data;
            }).fail(function (error) {

                this.isBusy = false;
                this._errorHandlerFunc(error);
                return null;
            });
        }
    }, {
        key: "loadLocationChildren",
        //loads the children of a location into the map

        value: function loadLocationChildren(parentId) {

            if (isNullOrEmpty(this._loadChildrenUrl)) return null;

            var found = this._locationData[parentId];

            if (found != null && found.childrenLoaded == true) {
                return found.children;
            }
            this.isBusy = true;

            $.post(this._loadChildrenUrl, {
                id: parentId
            }, function (data) {

                this._addLocations(data);
                this.isBusy = false;
                return data;
            }).fail(function (error) {

                this.isBusy = false;
                this._errorHandlerFunc(error);
                return null;
            });
            return null;
        }
    }, {
        key: "loadHierarchy",
        //loads a location and all parents up to root into the map

        value: function loadHierarchy(locationId) {
            if (isNullOrEmpty(locationId)) return null;
            if (isNullOrEmpty(this._loadHierachyUrl)) return null;

            this.isBusy = true;
            $.post(this._loadHierachyUrl, {
                id: locationId
            }, function (data) {

                this._addLocations(data);
                this.isBusy = false;
                return data;
            }).fail(function (error) {

                this.isBusy = false;
                this._errorHandlerFunc(error);
                return null;
            });
            return null;
        }
    }, {
        key: "_addLocations",
        value: function _addLocations(data) {
            if (data === undefined || data === null || data.length === 0) return;

            for (var i = 0; i < data.length; i++) {
                var node = data[i];
                this._locationData[node.Id] = node;
            }
        }
    }, {
        key: "loadHierarchyUrl",
        get: function get() {
            return this._loadHierachyUrl;
        },
        set: function set(value) {
            this._loadHierachyUrl = value;
        }
    }, {
        key: "loadLocationUrl",
        get: function get() {
            return this._loadLocationUrl;
        },
        set: function set(value) {
            this._loadLocationUrl = value;
        }
    }, {
        key: "loadChildrenUrl",
        get: function get() {
            return this._loadChildrenUrl;
        },
        set: function set(value) {
            this._loadChildrenUrl = value;
        }
    }, {
        key: "errorHandlerFunc",
        set: function set(func) {
            this._errorHandlerFunc = func;
        }
    }, {
        key: "isBusy",
        get: function get() {
            return Boolean(this._isBusy);
        },
        set: function set(value) {
            if (Boolean(value)) this._isBusy++;else {
                this._isBusy--;
                if (this._isBusy < 0) this._isBusy = 0;
            }
            pubSub.publish(isBusyChanged, this.isBusy);
        }
    }, {
        key: "selectedLocation",
        get: function get() {
            return this._selectedLocation;
        },
        set: function set(value) {
            if (value == this._selectedLocation) return;
            this._selectedLocation = value;
            pubSub.publish(selectedLocationChanged, this._selectedLocation);
        }
    }]);

    return LocationDataManager;
}();
Sam
  • 1,325
  • 1
  • 13
  • 26
  • 1
    In the callback of `$.post`, the context has changed, and `this` is no longer the instance of your class. Did you use an arrow function in your original code to make sure you keep the context? `(data) => { this._addLocation(data); /*...*/ }`. Babel should then take care of it while converting it back to a plain function. (do the same for the `.fail` callback) – blex Mar 23 '20 at 18:06
  • 1
    @blex Ah, that makes sense. I didn't use an arrow because I had trouble with them and IE11 before... but that was before I found Babel. I'll go change that and hopefully it will fix it. Thanks for the suggestion. – Sam Mar 23 '20 at 18:28

1 Answers1

1

The context of this is lost when the callback function is being executed. To solve that you can use an arrow function or use the bind method.

As you said you didn't use arrow functions, then you could try the bind method. I think it should be like this:

$.post(..., function(data) { this._addLocations(data); ...}).bind(this);

For the detailed information about how to access the correct this inside a callback, you could refer to this thread which has very detailed explanation.

Yu Zhou
  • 11,532
  • 1
  • 8
  • 22
  • Thanks. Per the previous suggestion I did use arrow functions to fix the issues I was having. However, I ran into another situation where I wasn't sure how to apply the arrow operator, but the bind method worked perfectly! – Sam Mar 24 '20 at 15:49