Search code examples
javascriptjqueryclassdesign-patternsprototype-programming

Access object context from prototype functions JavaScript


I have problems with object scope.

Here is my class code

// Table list module
        function DynamicItemList(data, settings, fields) {
            if (!(this instanceof DynamicItemList)) {
                return new DynamicItemList(data, settings, fields);
            }
            this.data = data;
            this.settings = settings;
            this.fields = fields;
            this.dataSet = {
                "Result": "OK",
                "Records": this.data ? JSON.parse(this.data) : []
            };
            this.items = this.dataSet["Records"];
            this.generateId = makeIdCounter(findMaxInArray(this.dataSet["Records"], "id") + 1);
            this.dataHiddenInput = $(this.settings["hidden-input"]);
        }

        DynamicItemList.RESULT_OK = {"Result": "OK"};
        DynamicItemList.RESULT_ERROR = {"Result": "Error", "Message": "Error occurred"};
        DynamicItemList.prototype = (function () {
            var _self = this;
            var fetchItemsList = function (postData, jtParams) {
                return _self.dataSet;
            };
            var createItem = function (item) {
                item = parseQueryString(item);
                item.id = this.generateId();
                _self.items.push(item);
                return {
                    "Result": "OK",
                    "Record": item
                }
            };
            var removeItem = function (postData) {
                _self.items = removeFromArrayByPropertyValue(_self.items, "id", postData.id);
                _self.dataSet["Records"] = _self.items;
                _self.generateId = makeIdCounter(findMaxInArray(_self.dataSet["Records"], "id") + 1);
                return DynamicItemList.RESULT_OK;
            };
            return {
                setupTable: function () {
                    $(_self.settings["table-container"]).jtable({
                        title: _self.settings['title'],
                        actions: {
                            listAction: fetchItemsList,
                            deleteAction: removeItem
                        },
                        fields: _self.fields
                    });
                },
                load: function () {
                    $(_self.settings['table-container']).jtable('load');
                },
                submit: function () {
                    _self.dataHiddenInput.val(JSON.stringify(_self.dataSet["Records"]));
                }
            };
        })();

I have problems with accessing object fields.

I tried to use self to maintain calling scope. But because it is initialized firstly from global scope, I get Window object saved in _self.

Without _self just with this it also doesn't work . Because as I can guess my functions fetchItemsList are called from the jTable context and than this points to Window object, so I get error undefined.

I have tried different ways, but none of them work.

Please suggest how can I solve this problem.

Thx.

UPDATE

Here is version with all method being exposed as public.

            // Table list module
        function DynamicItemList(data, settings, fields) {
            if (!(this instanceof DynamicItemList)) {
                return new DynamicItemList(data, settings, fields);
            }
            this.data = data;
            this.settings = settings;
            this.fields = fields;
            this.dataSet = {
                "Result": "OK",
                "Records": this.data ? JSON.parse(this.data) : []
            };
            this.items = this.dataSet["Records"];
            this.generateId = makeIdCounter(findMaxInArray(this.dataSet["Records"], "id") + 1);
            this.dataHiddenInput = $(this.settings["hidden-input"]);
        }

        DynamicItemList.RESULT_OK = {"Result": "OK"};
        DynamicItemList.RESULT_ERROR = {"Result": "Error", "Message": "Error occurred"};
        DynamicItemList.prototype.fetchItemsList = function (postData, jtParams) {
            return this.dataSet;
        };
        DynamicItemList.prototype.createItem = function (item) {
            item = parseQueryString(item);
            item.id = this.generateId();
            this.items.push(item);
            return {
                "Result": "OK",
                "Record": item
            }
        };
        DynamicItemList.prototype.setupTable = function () {
            $(this.settings["table-container"]).jtable({
                title: this.settings['title'],
                actions: this,
                fields: this.fields
            });
        };
        DynamicItemList.prototype.load = function () {
            $(this.settings['table-container']).jtable('load');
        };
        DynamicItemList.prototype.submit = function () {
            this.dataHiddenInput.val(JSON.stringify(this.dataSet["Records"]));
        };
        DynamicItemList.prototype.removeItem = function (postData) {
            this.items = removeFromArrayByPropertyValue(this.items, "id", postData.id);
            this.dataSet["Records"] = this.items;
            this.generateId = makeIdCounter(findMaxInArray(this.dataSet["Records"], "id") + 1);
            return DynamicItemList.RESULT_OK;
        };
        DynamicItemList.prototype.updateItem = function (postData) {
            postData = parseQueryString(postData);
            var indexObjToUpdate = findIndexOfObjByPropertyValue(this.items, "id", postData.id);
            if (indexObjToUpdate >= 0) {
                this.items[indexObjToUpdate] = postData;
                return DynamicItemList.RESULT_OK;
            }
            else {
                return DynamicItemList.RESULT_ERROR;
            }

        };

Solution

  • Thanks everyone for help, I've just figured out where is the problem.

    As for last version with methods exposed as public. Problematic part is

       $(this.settings["table-container"]).jtable({
                        title: this.settings['title'],
                        actions: {
                            listAction: this.fetchItemsList,
                            createAction: this.createItem,
                            updateAction: this.updateItem,
                            deleteAction: this.removeItem
                        },
                        fields: this.fields
                    });
                };
    

    Here new object is created which has no idea about variable of object where it is being created.

    I've I changed my code to the following as you can see above.

      $(this.settings["table-container"]).jtable({
                    title: this.settings['title'],
                    actions: this,
                    fields: this.fields
                });
    

    And now it works like a charm. If this method has drawbacks, please let me know. My problem was initially in this part and keeping methods private doesn't make any sense because my object is used by another library.

    Thx everyone.