I made an attempt to separate javascript on the search grid user control from the html in the .ascx file. In the first iteration I used the jQuery(document).onReady function to attach my intialization.
The problem with this is that <%= %> tags used within jQuery selectors were not interpolated correctly and the controls the javascript acted on were not found with the jQuery selectors.
Next, I attempted to create a json object in the Page initialization and write that out using the asp.net method Page.ClientScript.RegisterClientScriptBlock. This worked ok, but with drawbacks: hard wired the json object's name and keys in the asp.net file and javascript file. This is disadvantageous because now there exists "two points of truth" to maintain and further more there is the potential for name collision in the final rendered page.
The most elegant solution within the asp .net and utilizing jQuery is to create an ajax script behavior in javascript. Then within the asp codebehind register the script behavior's properties in the GetScriptDescriptors() method of the IScriptControl interface, adding the server side control's ClientID as a property to the script descriptor.
// Ajax Javacsript Code below:
Type.registerNamespace('SearchGrid');
// Define the behavior properties
//
ButtonBehavior = function() {
ButtonBehavior.initializeBase(this);
this._lnkSearchID = null;
}
// Create the prototype for the behavior
//
//
SearchGrid.ButtonBehavior.prototype = {
initialize: function() {
SearchGrid.ButtonBehavior.callBaseMethod(this, 'initialize');
jQuery('#' + this._lnkSearchID).click(function() { alert('We clicked!'); });
},
dispose: function() {
SearchGrid.ButtonBehavior.callBaseMethod(this, 'dispose');
jQuery('#' + this._lnkSearchID).unbind();
}
}
// Register the class as a type that inherits from Sys.Component.
SearchGrid.ButtonBehavior.registerClass('SearchGrid.ButtonBehavior', Sys.Component);
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
Asp .Net code below:
public partial class SearchGrid : System.Web.UI.UserControl, IScriptControl
{
// Initialization
protected override void OnPreRender(EventArgs e)
{
if (!this.DesignMode)
{
// Test for ScriptManager and register if it exists
ScriptManager sm = ScriptManager.GetCurrent(Page);
if (sm == null)
throw new ApplicationException("A ScriptManager control must exist on the current page.");
sm.RegisterScriptControl(this);
}
base.OnPreRender(e);
}
protected override void Render(HtmlTextWriter writer)
{
if (!this.DesignMode)
sm.RegisterScriptDescriptors(this);
base.Render(writer);
}
// IScriptControl Members
public IEnumerable<ScriptDescriptor> GetScriptDescriptors()
{
ScriptBehaviorDescriptor desc = new ScriptBehaviorDescriptor("SearchGrid.ButtonBehavior", this.ClientID);
desc.AddProperty("lnkSearchID", this.lnkSearch.ClientID);
yield return desc;
}
public IEnumerable<ScriptReference> GetScriptReferences()
{
ScriptReference reference = new ScriptReference();
reference.Path = ResolveClientUrl("SearchGrid.ButtonBehavior.js");
return new ScriptReference[] { reference };
}
}
The advantage here is that you may create stand alone reusable controls with javascript behavior contained in its own separate file (or as a web resource) while passing state and context, which might otherwise would be interpolated with angle,percent, equals syntax, necessary for jQuery to do its work.