This is a migrated thread and some comments may be shown as answers.

Client event handlers changes value of 'this'

1 Answer 49 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Vi Le
Top achievements
Rank 1
Vi Le asked on 12 Mar 2014, 04:48 PM
So I have a kind of interesting problem here. I am using the Telerik control suite for ASP.NET AJAX, inside a number of custom user controls.

When assigning client side event handlers, I have changed my approach from defining functions at the window scope, to using the $create method to create an object for my control, and assigning the control's client side event to a method defined on the prototype. Here is the basic setup:

From an external js file:

function genericControl_init(sender, args){
  $create(GenericObject, sender);
}
 
function GenericObject(){};
GenericObject.prototype = {
  someFunction: function (sender, args) {
    console.log(this.someProperty)//undefined
    console.log(this);//this is not the GenericObject
  },
  get_id: function () { return this.id },
  set_id: function (id) { this.id = id },
  beginUpdate: function () { return true },
  endUpdate: function () { return true }
}

And on the page, generated in the code behind, this uses the control's ClientID for the id property on the JSON object:
genericControl_init({ "id": "ct101_someControl", "someProperty": "ct101_someControl_someClientID" });

and in the codebehind, to assign the event:
RadComboBox1.OnClientSelectedIndexChanged = String.Format("$find('{0}').{1}", ClientID, "someFunction");

This is just using a RadComboBox as an example, this happens with any Telerik control. Basically, it appears that the scope of this has changed when assigning the function as an event handler for a Telerik control and no longer references my GenericObject object.

A workaround I have found is storing the ClientID as an attribute on the Telerik control, and then grabbing it like sender.get_attributes().getAttribute('controlClientId') and using $find to get the reference to the original object and access it's individual properties. This feels sloppy though, and I was just wondering if anyone had a suggestion on how to better handle this.

1 Answer, 1 is accepted

Sort by
0
Accepted
Ivan Zhekov
Telerik team
answered on 17 Mar 2014, 08:51 AM
Hello.

Examine the following snippet:

<telerik:RadComboBox runat="server" OnClientSelectedIndexChanged="mediator.someFunction">
    <Items>
        <telerik:RadComboBoxItem Text="1" />
        <telerik:RadComboBoxItem Text="2" />
    </Items>
</telerik:RadComboBox>
 
 
<script>
    var Generic =  function() {};
    Generic.prototype = {
        someFunction: function( sender, args ) {
            console.log( this )
        }
    }
 
    var instance = new Generic();
 
    var fn2 = instance.someFunction;
 
    instance.someFunction();
    fn2();
 
    var mediator = {
        someFunction : function() {instance.someFunction()}
    }
 
</script>

Notice the highlighted lines. Just by looking at it we would expect both to do the same thing. They actually do so, but the thing is that with this value assignment, the bound this is lost and refers to the window.

Something similar happens in the case of OnClientEventName, but this is bound to the function. By the way, that's not something we are doing. Instead we rely on the clientside ASP.NET Ajax framework and it's the framework that binds this to function. It's worth mentioning that almost every framework re-binds this to the object that seems most fit.

One way to do workaround the issue is to use function mediator (or mediator object) as shown in the snippet.

Regards,
Ivan Zhekov
Telerik
 

DevCraft Q1'14 is here! Watch the online conference to see how this release solves your top-5 .NET challenges. Watch on demand now.

 
Tags
General Discussions
Asked by
Vi Le
Top achievements
Rank 1
Answers by
Ivan Zhekov
Telerik team
Share this question
or