Home     About PeterBlum.com     Policies     Download a Licensed Product     Newsletter
RegisterScripts  
Current Release: 1.0.0  
Jump to: Download

RegisterScripts is a substitute for the System.Web.UI.Page class methods IsClientScriptBlockRegistered, IsStartupScriptRegistered, RegisterClientScriptBlock and RegisterStartupScript. It provides these enhancements to the process of registering scripts:
  • It fixes a problem with Microsoft’s methods where they are not always written to the page in a specific order. This WILL break order dependent client-side initialization code on pages where code and controls register 9 or more scripts. If you build a custom control that has ANY order dependent initialization code, in the field your control will break.
  • It allows you to omit <script> tags. It inserts them for you, often grouping several scripts under a common tag for better formatting and smaller page size.
  • It allows you to determine ordering on the page when scripts are dependant on others that come before them.

Problem With Microsoft’s Script Registration Methods

Often users developing client-side JavaScript include initialization code. That is code which runs when the page is loading. To be initialization code, it must be statements that are not enclosed in a JavaScript function. For example:

var gGlobalVar = false;  // Here is initialization code
function Test()
{
// do something here
  gGlobalVar = true;  // Depends on gGlobalVar being declared first
}
Test();  // Here is initialization code that depends on Test being declared first

The RegisterClientScriptBlock and RegisterStartupScript methods have the following problem that can break client-side script initialization code:

As you add scripts to the Client Scripts and Startup Scripts areas of the page, the entries are added to the page in the order they are registered with the RegisterClientScriptBlock and RegisterStartupScript methods. This is predictable and useful behavior, especially when one initialization script is dependent on another. Microsoft implemented these methods by storing your scripts in a System.Collections.Specialized.HybridDictionary that changes from a ListDictionary to a HashTable at a certain point. In this case, they made it switch at 9 calls. Once in a Hashtable, the ordering is lost and the scripts are written to the page in a random order.

Example

[C#]

public void Page_Load(object sender, System.EventArgs e)
{
  int vCount = 8;
  for (int vI = 0; vI < vCount; vI++)
    RegisterScripts.RegisterClientScriptBlock(this, "Block" + vI.ToString(),
      "<script language='JavaScript'> // Code for " + vI.ToString() + "</script>\n");
}

[VB]

Public Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
  Dim vCount As Integer = 8
  For vI = 0 To vCount – 1
    RegisterScripts.RegisterClientScriptBlock(Me, _
      "Block" + vI.ToString(), _
      "<script language='JavaScript'> // Code for " + vI.ToString() + "</script>" + chr(13))
  Next
End Sub

This will write:

<script language=’JavaScript’> // Code for 0</script>
<script language=’JavaScript’> // Code for 1</script>
<script language=’JavaScript’> // Code for 2</script>
...
<script language=’JavaScript’> // Code for 8</script>

Change vCount to 9 and the order is not predictable:

<script language=’JavaScript’> // Code for 3</script>
<script language=’JavaScript’> // Code for 8</script>
<script language=’JavaScript’> // Code for 1</script>
...
<script language=’JavaScript’> // Code for 5</script>

Even if you only use two calls to RegisterClientScriptBlock or RegisterStartupScript, other controls and code running on the same page will add calls to the same methods. At some point, the combination of all calls to these methods will exceed 8 calls and the order will be randomized. If you depend on the order, your code will break.

Let's suppose you created the initialization code at the top of this page using three calls to RegisterClientScriptBlock() from within a custom control.

this.Page.RegisterClientScriptBlock("Key1", "var gGlobalVar = false;\n");
this.Page.RegisterClientScriptBlock("Key2",
    "function Test()\n{\n// do something here\n gGlobalVar = true;\n}\n");
this.Page.RegisterClientScriptBlock("Key3", "Test();\n");

When this custom control is on a page that includes 6 more calls to RegisterClientScriptBlock, your JavaScript may look like this and it will break:

Test(); // Here is initialization code that depends on Test being declared first
function Test()
{
// do something here
  gGlobalVar = true; // Depends on gGlobalVar being declared first
}
var gGlobalVar = false; // Here is initialization code

How RegisterScripts Fixes The Problem

RegisterScripts is a tool that provides substitutes for the four script registration methods on the page class while maintaining the order. It can be used on a page where other controls and code continues to use Microsoft’s methods. In fact, it eventually uses Microsoft’s RegisterClientScriptBlock and RegisterStartupScript to write to the page. However, it only makes one call, after formatting all your registered scripts into a single string.

Making Script Tags Optional

Normally, you need to supply the start and end <script> tags to your scripts. With RegisterScripts, these become optional. When you let RegisterScripts add them for you, you get many benefits:

  • You don’t have to declare them in the script passed in which simplifies your code to just the JavaScript itself.
  • RegisterScripts will define the script tags consistently. This limits errors, such as forgetting to put <!-- //--> tags around each script.
  • You can change the format of the tags universally with global properties in RegisterScripts. For example, if you prefer to use the <script> tag attribute type=text/javascript instead of language='JavaScript', you can switch it quickly.
  • All back-to-back calls to register your scripts will be enclosed in a common set of script tags. It reduces the page size and makes the code more readable. For example, if you register two scripts, when you supply the scripts tags yourself, it looks like this:

    <script language=’JavaScript’>
    <!--
    //code for script #1
    // -->
    </script>

    <script language=’JavaScript’>
    <!--
    //code for script #2
    // -->
    </script>


    When RegisterScripts adds the script tags, it looks like this:

    <script language=’JavaScript’>
    <!--
    //code for script #1
    //code for script #2
    // -->
    </script>

    Microsoft’s use of extra space between each script is also removed.

Controlling Script Order On The Page

Most of the time, you want your scripts to be ordered on the page in the order the RegisterClientScriptBlock and RegisterStartupScript block are called. However, if you use a number of calls to build a sequence of scripts, you may need more control over order.

RegisterScripts allows you to define a group number to which each script is assigned. If you do not supply a group number, all are added to group number 0. When you supply a group number, all scripts with the same group number will be positioned on the page in the order they were added within the group. Groups with a lower number are positioned higher on the page.

For instance, all scripts with the group number 1 will be output together and appear below group 0 (the default group). With this, you can be very precise about the order.

Example

Suppose you are writing a TreeView custom control where each node must write some initialization code to the page. First the node writes a reference to a script file that contains the functions it needs to initialize. This must happen only once. Then it calls the initialization function.

[C#]

public void RegisterNodeScripts()
{
  if (!RegisterScripts.IsClientScriptBlockRegistered(Page, "TreeViewScriptFile"))
    RegisterScripts.RegisterClientScriptBlock(Page, "TreeViewScriptFile",
      "<script language='JavaScript' src='/aspnet_client/TreeView.js'/>",
      false,    // user supplies script tags
      1);      // group 1
  RegisterScripts.RegisterClientScriptBlock(Page, "NodeID_" + ID,
    "InitTreeNode('" + ID + "');",
    true,    // RegisterScripts supplies the script tags
    2);      // group 2
}

[VB]

Public Sub RegisterNodeScripts()
  If Not RegisterScripts.IsClientScriptBlockRegistered(Page, _
      "TreeViewScriptFile"))
    RegisterScripts.RegisterClientScriptBlock(Page, "TreeViewScriptFile", _
      "<script language='JavaScript' src='/aspnet_client/TreeView.js'/>", _
      False, _    ' user supplies script tags
      1)      ' group 1
  End If
  RegisterScripts.RegisterClientScriptBlock(Page, "NodeID_" + ID, _
    "InitTreeNode('" + ID + "');", _
    True, _    // RegisterScripts supplies the script tags
    2)      // group 2
End Sub

The result of 5 nodes calling their RegisterNodeScripts method is the following on the page:

<script language='JavaScript' src='/aspnet_client/TreeView.js' />
<script language='JavaScript'>
<!--
InitTreeNode('Node1');
InitTreeNode('Node2');
InitTreeNode('Node3');
InitTreeNode('Node4');
InitTreeNode('Node5');
// -->
</script>

Download

Product RegisterScripts
Version 1.0 (Current release: 1.0.0)
Price Free
Restricted Usage Read the License Agreement
Source Code Included
Language C#
Compatibility Microsoft .Net 1.0 and 1.1

Download this file