-1

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;
            }

        };
CROSP
  • 4,499
  • 4
  • 38
  • 89
  • The whole point of the prototype is that the methods are shared any need to use `this` inside the method body?! You can use that `_self` approach only inside the constructor where you actually have an instance already. – Bergi Oct 28 '16 at 09:16
  • Yes you are right, this is doesn't work, this is just an example how I tried to solve and I explained why this is not working, I am looking for other solution. So I asked this question. – CROSP Oct 28 '16 at 09:22
  • Possible duplicate of [JavaScript private methods](http://stackoverflow.com/questions/55611/javascript-private-methods) – cнŝdk Oct 28 '16 at 10:22
  • 1
    @chsdk as you may see, I've already used approach form this link, but the problem was in other part of the code. – CROSP Oct 28 '16 at 10:25

3 Answers3

0

Your assigning a function directly to the prototype. DynamicItemList.prototype= Normally it's the form DynamicItemList.prototype.somefunc=

Keith
  • 22,005
  • 2
  • 27
  • 44
  • Yes, but as you can see, this function is self executing and returns object itself which contains some other functions. I have done this because of private methods. Is it possible to keep methods private and expose only specific parts, like I did, but make it work) – CROSP Oct 28 '16 at 09:11
0

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.

CROSP
  • 4,499
  • 4
  • 38
  • 89
0

You need to make your prototype methods use the this keyword (so that they dyynamically receive the instance they were called upon), but you need to bind the instance in the callbacks that you pass into jtable.

DynamicItemList.prototype.setupTable = function () {
    var self = this;
    function fetchItemsList(postData, jtParams) {
        return self.dataSet;
    }
    function createItem(item) {
        item = parseQueryString(item);
        item.id = self.generateId();
        self.items.push(item);
        return {
            "Result": "OK",
            "Record": item
        };
    }
    … // other callbacks

    $(this.settings["table-container"]).jtable({
        title: this.settings['title'],
        actions: {
            listAction: fetchItemsList,
            createAction: createItem,
            updateAction: updateItem,
            deleteAction: removeItem
        },
        fields: this.fields
    });
};
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375