Aug 10th 2008 09:24 am
Properly using the “references” parameter to the MS Ajax $create statement
Suppose you want to reference a component from another component. The MS Ajax documentation gives the following explanation of the $create function:
Syntax
$create(type, properties, events, references, element);Arguments
Parameter Description type The type of the component to create. properties (Optional) A JSON object that describes the properties and their values. events (Optional) A JSON object that describes the events and their handlers. references (Optional) A JSON object that describes the properties that are references to other components. element (Optional) The DOM element that the component must be attached to.
The documentation doesn’t provide much information, however, on why you should use the references parameter instead of just using the $find method in the initialize event of your component.
When the framework renders $create statements through the scriptmanager, each script descriptor becomes a $create statement in the page source. These statements are executed by the ajax framework when page_load. In order for a component instance to reference another component instance, the object being referenced has to exist already. If the $create statement for the object being referenced comes after the referencing component’s $create, an error will occur when the $find method is called.
One way around this is to execute $find every time that the component needs to be referenced. This has performance implications and doesn’t scale well when dealing with collections of components.
Another way around this is to use the MS Ajax Application_load event using code similar to the following:
MyNamespace.MyComponent.prototype = {
initialize: function() {
MyNamespace.MyComponent.callBaseMethod(this, 'initialize');
this._applicationLoadHandler = Function.createDelegate( this, this.applicationLoad );
Sys.Application.add_load( this._applicationLoadHandler );
},
applicationLoad: function(sender, e) {
this._componentReference = $find(this._componentReferenceId);
//Remove the LoadHandler
Sys.Application.remove_load( this._applicationLoadHandler );
this._applicationLoadHandler = null;
},
set_ComponentReferenceId : function( value ) {
this._componentReferenceId = value;
},
get_ComponentReferenceId : function() {
return this._componentReferenceId;
}
// other code
}
This approach is explicit and therefore more clear to other developers who might inherit your code. Additionally for collections of components, this method is an excellent option.
The framework does, however, does provide a way to ensure that when the initialize method is called, the component references have already been set just like other component properties.
If our custom component inherits from AjaxControlToolkit.ExtenderControlBase, we can add the AjaxControlToolkit.ComponentReference attribute to the property declaration
<AjaxControlToolkit.RequiredProperty()> _
<AjaxControlToolkit.ExtenderControlProperty()> _
<IDReferenceProperty()> _
<AjaxControlToolkit.ComponentReference()> _
<AjaxControlToolkit.ClientPropertyName("ComponentReference")> _
Public Property ComponentReferenceId() As String
Get
Return GetPropertyValue(Of String)("ComponentReferenceId", String.Empty)
End Get
Set(ByVal value As String)
SetPropertyValue(Of String)("ComponentReferenceId", value)
End Set
End Property
Note: we also need to change the getter/setter methods in the javascript to:
set_ComponentReference : function( value ) {
this._componentReference = value;
},
get_ComponentReference : function() {
return this._componentReference;
}
Before the initialize method is called the framework will now call set_ComponentReference and pass $find(value from the server side property) as the sole parameter.
If you’re not extending from AjaxControlToolkit.ExtenderControlBase, you can perform the same operation by using the SetComponent method in the GetScriptDescriptors method:
Protected Overrides Function GetScriptDescriptors(ByVal targetControl As System.Web.UI.Control) As System.Collections.Generic.IEnumerable(Of System.Web.UI.ScriptDescriptor)
Dim descriptor As New ScriptBehaviorDescriptor("MyNamespace.MyComponent", targetControl.ClientID)
descriptor.AddComponentProperty("ComponentReference",Me.ComponentReference)
...
Return New ScriptDescriptor() {descriptor}
End Sub
In either event, the net result should be a statment similar to the following generated by the framework in the page source:
Sys.Application.add_init(function() {
$create(MyNamespace.MyComponent, {…,”id”:”CustomComponentId”}, null, $find(”RefefencedBehaviorId”), $get(”targetControlId)”));
});
No Comments yet »