1

So I am writing something using augment for inheritance and for some reason I can run this.setButtons(type) and console.log(this.buttons) in that method, but when I run my this.getButtons() it comes back as undefined, even though getButtons just returns this.buttons. Any help would be greately appreciated. I will post up all the code I have so far, because maybe I'm not inheriting properly. Thank you in advance.

var ContextMixin = function () {};
ContextMixin.prototype = {
    createElements: function (el, mode, type) {
        var m;
        if (mode == 'exact') {
            $("#" + el).append("<ul id='contextmenu'>");
        } else {
            $(el).each(function () {
                m = $(this).append("<ul id='contextmenu'>");
            });
            $('body').append(m);
        }
        $("#contextmenu").css({
            'position': 'absolute',
            top: 13,
            left: 13
        });
        var new_buttons = this.getButtons();
        $.each(this.buttons['buttons'], function () {
            m.append("<li id='" + this + "'>" + this + "</li>");
        });
    },
    attachEvents: function () {
        functions = this.getFunctions(type);
        buttons = this.getButtons();
        for (index in buttons['buttons']) {
            addEvent(buttons['buttons'][index], this.functions[index][0], this.functions[index][1]);
        };
    },
    setFunctions: function (type) {
        var callback = {
            success: function (msg) {
                this.functions = msg;
            },
            failure: function () {
                alert('Error getting functions')
            }
        };
        $.ajax({
            type: 'GET',
            url: 'function_list.php?type=' + type,
            success: function (msg) {
                this.functions = msg;
            }
        });
    },
    getFunctions: function () {
        return this.functions;
    },
    setType: function (value) {
        this.type = value;
    },
    getType: function () {
        return this.type;
    },
    setButtons: function (type) {
        $.ajax({
            type: 'GET',
            url: 'button_list.php?type=' + type,
            success: function (reply) {
                this.buttons = reply;
            }
        });
    },
    getButtons: function () {
        return this.buttons;
    }
}

function createMenu(el, type, mode) {
    this.setButtons(type);
    this.setFunctions(type);
    this.createElements(el, mode, type);
}

augment(createMenu, ContextMixin);

function augment(receivingClass, givingClass) {
    if (arguments[2]) { //Only give certain methods.
        for (var i = 2, len = arguments.length; i < len; i++) {
            receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];
        }
    } else { //Give all methods
        for (methodName in givingClass.prototype) {
            if (!receivingClass.prototype[methodName]) {
                receivingClass.prototype[methodName] = givingClass.prototype[methodName];
            }
        }
    }
}

3 Answers 3

2

Because this in the callback to the AJAX request is not your object.

Here's a common fix...

setButtons: function(type) {
    var self = this;  // keep a reference to this
    $.ajax({
        type: 'GET', 
        url: 'button_list.php?type=' + type,
        success: function(reply) {
            self.buttons = reply; // use the reference here
        }
    });
},

...but a better fix is to use the context: property of the $.ajax request...

setButtons: function(type) {
    $.ajax({
        type: 'GET', 
        context: this,  // set the context of the callback functions
        url: 'button_list.php?type=' + type,
        success: function(reply) {
            this.buttons = reply;
        }
    });
},
Sign up to request clarification or add additional context in comments.

5 Comments

I had no idea there was a context property on the ajax calls. That's cool. I wish I could +1 again. Odd you haven't gotten more for this answer. I guess the community is sick of "this isn't what it should be" questions :)
@AdamRackis: Yes, the context is a nice clean way to do it, assuming you don't need access to the jqXHR object.
If I do that and set self = this or use the context in the ajax call and in my main function do this...function createMenu(el, type, mode) { this.setButtons(type); console.log(this.buttons); this.setFunctions(type); this.createElements(el, mode, type); } it logs undefined
@Rob: That's because your $.ajax request is asynchronous, so the console.log runs before the request is complete. In other words, code that comes after your this.setButtons(type); code will run immediately instead of waiting for the response. Any code that relies on the response must be called from within your success: callback to the request.
figured it out. when doing the inheritance with augment the prototype methods can't use the other methods in the prototype at instantiation. you have to var method = new class(opts); method.setButtons(type); var buttons = method.getButtons();
0

If you change

ContextMixin.prototype = {
createElements

to

ContextMixin.prototype.createElements

it should work.

1 Comment

OP is replacing the entire prototype object. That's allowed.
0

this is not what you think it is in your ajax callback—instead of being your current object, it's actually the global object the XHR object. All your callback is doing is putting a buttons property onto the xhr object.

You need to save this before your function runs:

setButtons: function(type) {
    var self = this;
    $.ajax({
        type: 'GET', 
        url: 'button_list.php?type=' + type,
        success: function(reply) {
            alert(reply);
            self.buttons = reply;
        }
    });
},

1 Comment

The default this value in the callback the jqXHR object.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.