Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / CSS

Including JavaScript/CSS into a Master Page from a Child Page as a User Control

4.33/5 (3 votes)
22 Apr 2010CPOL5 min read 1   337  
This article describes the method of including the JavaScript/CSS as a user control into a master page from: a child page, a user control included in the child page, a web control included in the child page.
JsUserControl.jpg

Introduction

This article deals with the problem of including the JavaScript and CSS styles into the sections of the master page from a child page. While there have been many articles and posts dealing with the problem, so far the author has not found a satisfactory solution that deals with passing the 'Client IDs' to the included JavaScript file. Another problem solved here is being able to have the syntax highlighting for included scripts.

Background

As it is well known, there are many ways to include the JavaScript into the head section of the master page. This can be accomplished easily, i.e., using the stock 'RegisterClientScriptInclude', 'RegisterStartupScript' or 'RegisterClientScriptBlock' methods. The drawback of the last two is that this has to be done from the code behind as the plain string without the syntax highlighting available. While we have the syntax highlighting at the disposal for the script included with the 'RegisterClientScriptInclude' method, we cannot pass the client ids to it! Rick Strahl deals with the problem of passing the client ids in ['http://www.west-wind.com/weblog/posts/252178.aspx']. There is also an article on CodeProject [http://www.codeproject.com/KB/aspnet/resource_files_in_asp_net.aspx?display=Print] that tries to solve this problem by storing the JavaScript in the resource file. The [http://www.dougv.com/blog/2010/02/17/dynamically-adding-javascript-to-your-asp-net-master-page-from-a-child-page/] reviews the common approaches to the problem as well as proposes the solution.

My Solution

The author of this article proposes the solution that accomplishes the following:

  • Placing the JavaScript and the CSS in the head section or right above the closing <\form > tag of the master page from the child page
  • JavaScript and CSS syntax highlighting available of the included script
  • Client ids passing as strongly typed properties
All three features have been achieved by using the user control that holds our JavaScript and CSS. A user control can be loaded dynamically into any master's page placeholder from a child page. We pass the client ids to the JavaScript through the control's public properties. If a placeholder is placed in the head section, we are achieving the equivalent of the 'RegisterClientScriptInclude' and 'RegisterClientScriptBlock' methods. If placed right above the <\form > tag of the master page, we mimic the functionality of the 'RegisterStartupScript' method.

Understanding the Code

The sample application demonstrates including the JavaScript and CSS in four different ways:

  • Including the JavaScript /CSS from the child page "default.aspx" into master page "Master.master" (just before the closing <\form > tag). This is an equivalent of the "RegisterStartupScript" method.
  • Including the JavaScript /CSS from the child page "default.aspx" into master page "Master.master" (into the head section). This is an equivalent of the "RegisterClientScriptBlock/RegisterClientScriptInclude" methods
  • Including the JavaScript /CSS from the web control "WebControl.cs" included in the child page into the master page "Master.master" (into a head section). This is an equivalent of the "RegisterStartupBlock/RegisterClientScriptInclude" methods
  • Including the JavaScript /CSS from the user control "WebUserControl.ascx" included in the child page into the master page "Master.master" (into a head section). This is an equivalent of the "RegisterStartupBlock/RegisterClientScriptInclude" methods.

In all four cases, we have the input form. The included JavaScript e.g. in the first case inside the user "CtrWithJs.ascx" takes care of reading the form's content and displaying it on the screen. We pass the input field ids to the control through its properties. Styling of the form is accomplished by including the CSS also inside the "CtrWithJs.ascx" control.

Using the Code

The usage of code is very simple. The "default.aspx" page loads dynamically two user controls "CtrWithJs2.ascx" and "CtrWithJs.ascx" containing javascript/css into the "Master.master" page. This is done in the "Page_PreRender" of the child "default.aspx" page. In the case of the former control, we load the "CtrWithJs2.ascx into the "ContentPlaceHolder2" just before the closing <\form > tag, in the latter directly into the master's page header section with the "runat" attribute. As we can see, all the "client ids" are passed through the properties.

C#
protected void Page_PreRender(object sender, EventArgs e)
{
    var ctrlWithJs = (CtrWithJs)LoadControl("CtrWithJs.ascx");
    var ctrlWithJs2 = (CtrWithJs2)LoadControl("CtrWithJs2.ascx");

    ctrlWithJs.textBox1Id = txt1.ClientID;
    ctrlWithJs.textBox2Id = txt2.ClientID;
    ctrlWithJs2.textBox3Id = txt3.ClientID;
    ctrlWithJs2.textBox4Id = txt4.ClientID;

    Master.Page.Header.Controls.Add(ctrlWithJs);
    var bottomPl = (ContentPlaceHolder)Master.FindControl("ContentPlaceHolder2");

    bottomPl.Controls.Add(ctrlWithJs2);
}

Sometimes, we may use a user control e.g. "WebUserControl.ascx" on the page. In that case, a user control itself loads dynamically our container user control "CtrWithJs4.ascx" to e.g. a head section of the master page, i.e.:

C#
protected void Page_PreRender(object sender, EventArgs e)
{
    var ctrlWithJs4 = (CtrWithJs4)LoadControl("CtrWithJs4.ascx");

    ctrlWithJs4.textBox11Id = WebUserControltxt1.ClientID;
    ctrlWithJs4.textBox12Id = WebUserControltxt2.ClientID;

    Page.Master.Page.Header.Controls.Add(ctrlWithJs4);
}

What if we would like to use a web control i.e. "WebControl.cs" that loads its own javascript/css? The approach is almost the same.

C#
protected override void OnPreRender(EventArgs e)
{
    base.OnPreRender(e);

    Control ctrlWithJs3 = Page.LoadControl("CtrWithJs3.ascx");

    ((IClientIdInterface3)ctrlWithJs3).textBox1Id = txtBox1.ClientID;
    ((IClientIdInterface3)ctrlWithJs3).textBox2Id = txtBox2.ClientID;

    Page.Master.Page.Header.Controls.Add(ctrlWithJs3);
}

As we can see, we run into slight complication with how we pass client ids into the javascript/css container control "CtrWithJs3.ascx". In order to accomplish that a container user control implements an interface "IClientIdInterface3",

C#
public interface IClientIdInterface3
{
    string textBox1Id { get; set; }
    string textBox2Id { get; set; }
}

containing only the string properties used to pass client ids,

C#
using System;
public partial class CtrWithJs3 : System.Web.UI.UserControl, IClientIdInterface3
{
    public string textBox1Id { get; set; }
    public string textBox2Id { get; set; }
}

The container user control holds the syntax highlighted javascript/css:

ASP.NET
<%@ Control Language="C#" AutoEventWireup="true" 
	CodeFile="CtrWithJs3.ascx.cs" Inherits="CtrWithJs3" % >
<script type="text/javascript">

    function ReadTTxt5() {
        var inputParam = '<%=textBox1Id%>';
        alert(document.getElementById(inputParam).value);
    }
    function ReadTTxt6() {
        var inputParam = '<%=textBox2Id%>>';
        alert(document.getElementById(inputParam).value);
    }
</script>
<link rel="Stylesheet" href="StyleSheet3.css" title="Contemporary" />

Javascript/CSS Caching

In order to take advantage of javascript/CSS caching by a browser we can rewrite the above "CtrWithJs3.ascx"  javascript container user controls as follows,

ASP.NET
<%@ Control Language="C#" AutoEventWireup="true"  CodeFile="CtrWithJs3.ascx.cs" 
    Inherits="CtrWithJs3" % > 
<script type="text/javascript">
    var inputParam5 = '<%=textBox1Id%>';
    var inputParam6 = '<%=textBox2Id%>';
</script>
<script type="text/javascript" src="WebUserConrolScript.js" ></script>
<link rel="Stylesheet" href="StyleSheet3.css" title="Contemporary" />
where "WebUserConrolScript.js" has the form,
JavaScript
 function ReadTTxt5() {
 alert(document.getElementById(inputParam5).value);
}
function ReadTTxt6() {
 alert(document.getElementById(inputParam6).value);
}
and will get cached by the browser.   "StyleSheet3.css"  stylesheet will get cached too.

Conclusions

As mentioned in the "Background" section, the problem dealt with here has been addressed countless times in many internet forums. What the author of this article finds unique is using user controls as the container for JavaScript and CSS. By doing that, we have a syntax highlighting available as well as we can pass client ids as strongly typed properties. We showed here that this can be accomplished from the regular child page, user control used on the child page, web control used on the child page.  Included javascript  files and CSS styles are also  cached by the browser.

History

  • 11th April, 2010: Initial version
  • 22nd April, 2010: Adding javascript  caching  feature

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)