2

I'm building a jQuery app using OOP principles and I'm trying to implement a externally added callback function which invokes a method from inside of my object.

function testObject() {
    var self = this;

    var functions = new Array();

    this.updateObject = function() {
        console.log('updated')
    }

    this.addFunction = function(func) {
        functions.push(func)
    }

    this.callFunctions = function() {
        $.each(functions, function(key, value) {
            functions[key]()
        })
    }
}



var myobject = new testObject();
myobject.addFunction(
        function() {
            $(':text').on('change', function() {
                return self.updateObject();
            })
        }
)

This is an overly simplified version of the plugin I'm building. The callback works fine, but I cannot use the self.updateObject(); inside of it, since it outputs Illegal Invocation.

How can I call a method from inside the callback properly?

2 Answers 2

2

The problem is self is out of scope of the callback function, because the function only has variables in the scope of where it was defined. The callback is defined outside of the testObject.

A solution is to bind the this context in the callback function to self using Function.prototype.call(self), when you call it in callFunctions(). Then in the callback, you can use this to refer to the testObject instance. In your callback example it contains a jQuery event so you will lose the this context. To rectify that you can create a local self that equals this before the jQuery change event.

function testObject() {
    var self = this;

    var functions = new Array();

    this.updateObject = function() {
        console.log('updated')
    }

    this.addFunction = function(func) {
        functions.push(func)
    }

    this.callFunctions = function() {
        $.each(functions, function(key, value) {
            functions[key].call(self); // call it and bind the context to self
        })
    }
}

var myobject = new testObject();
myobject.addFunction(
        function() {
            var self = this; // needed because the change event will overwrite 'this'
            $(':text').on('change', function() {
                return self.updateObject(); // use self to access testObject
            })
        }
)
myobject.callFunctions();

Alternatively you can pass self as an argument to the callback. To do that, change the .call() line to:

functions[key].call(null, self);

and change the callback to accept an argument like so:

myobject.addFunction(
        function(self) { // self as an argument
            $(':text').on('change', function() {
                return self.updateObject(); // use self to refer to testObject
            })
        }
)
Sign up to request clarification or add additional context in comments.

2 Comments

Hi MrCode! Thank you very much for your complex answer. I'm still getting the same error unfortunately. Uncaught TypeError: Illegal invocation. I've tried calling it in many ways, and it doesn't work, even though it theoretically should.
Edit. I got it right the first time. The problem was in the updateObject() method which was calling a method illegally. Thank you for your help
0
function testObject() {
    var self = this;

    var functions = new Array();

    this.updateObject = function() {
        console.log('updated')
    }

    this.addFunction = function(func) {
        functions.push(func.bind(self)) // Bind the context
    }

    this.callFunctions = function() {
        $.each(functions, function(key, value) {
            functions[key]()
        })
    }
}

var myobject = new testObject();

myobject.addFunction(
        function() {
            var self = this;

            $(':text').on('change', function() {
                return self.updateObject();
            })
        }
)

Or you can use this as well:

 myobject.addFunction(
            function() {    
                $(':text').on('change', this.updateObject);
            }
    )

Comments

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.