5

Say I have the following defined in javascript:

com.company.long.namespace = {
    actions: {   
        add: {  
            defaults: {
                url: 'myurl/submit',
            },

            invoke: function () {   
                var submitUrl = this.defaults.url;                          
                com.company.long.namespace.foo.util.server.submit({
                    url: submitUrl,
                    success: function() { }
                });
            },
        }
    }
};

which I then call with within the context of a JQuery click event:

$(myElem).click(function() {
    com.company.long.namespace.actions.add.invoke();
});

Because of the way 'this' works within jQuery event callbacks, this.defaults is undefined when called from this context. Is there anyway to still make use of 'this' within this scope, without having to define the full namespace, or without using jQuery.proxy?

cweston
  • 11,297
  • 19
  • 82
  • 107

2 Answers2

5

You can't call add, it's not a function.

If you call the add.invoke function, this.default is the default object that you have defined in the add object. You don't have to do anything special.

Example: http://jsfiddle.net/p4j4k/

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • @Guffa - Thanks for the example, thats odd because I swore I had been seeing different functionality in my actual code. I see that this is definitely working though in your example. The missing invoke was merely a typo when porting my code to an example. Thanks though. – cweston May 03 '11 at 20:24
  • @Guffa - I have implemented a more accurate example: http://jsfiddle.net/p4j4k/16/ which demonstrates the undefined behaviour I am seeing – cweston May 03 '11 at 20:40
  • I suspect that in your code you may be using function prototypes or initialized objects/functions where the "this" object is not what you expected. Use console.log(this) and use the dev console, should help you to find out what is causing the problem. – user120242 May 03 '11 at 20:41
  • http://jsfiddle.net/p4j4k/17/ Looks like my suspicion was correct. The "this" object is actually the "options" parameter, because options.callback() is actually doing callback.apply(options) – user120242 May 03 '11 at 20:49
  • @user120242 - Yes I noticed that as well. Do you know why apply is being used with 'options'. This seems odd. – cweston May 03 '11 at 20:55
  • @leaf dev: That's not odd at all. The `callback` is a member of the `options` object, so when you call the method it gets the object as scope, as usual. By copying the function into the object you detach it from it's original object. You can put an anonymous function in the object, that calls `invoke` to keep the scope: http://jsfiddle.net/p4j4k/25/ – Guffa May 03 '11 at 21:03
  • @Guffa: To be fair, it is a bit odd. It creates all sorts of confusing oddities, like this one: http://stackoverflow.com/questions/2261342/can-somebody-explain-this-javascript-method – user120242 May 03 '11 at 21:06
  • Also this brings up a good point. When assigning functions in objects, it's almost always a good idea to wrap them in anonymous functions before assigning, unless it is specifically intentional. Tends to cause all sorts of scope confusion. – user120242 May 03 '11 at 21:13
0

To call a function with a context of your choosing you can use .apply(context) (more info about function.apply and function.call):

com.company.long.namespace.actions.add.invoke.apply(com.company.long.namespace.foo.util.context);

Within the invoke function this will refer to the context object.
Check this jsFillde example

Dan Manastireanu
  • 1,802
  • 1
  • 15
  • 18