Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebForms: Dynamic (or absolute) script tags in MasterPages

Problem

When working with MasterPages, a common irritation I run into is that script tags in the master are relative to the consuming page.

So for instance, your JavaScript might work if your consuming page is in the root of your app, but when you put another page in a subfolder, the relative path breaks and the JavaScript is not found. And there isn't a way to use absolute paths that I'm aware of in this case.

This last time, I decided to really attack this and find a good solution.

Proposed Solutions

I tried one strategy that revolved around calling ClientScriptManager.RegisterClientScriptInclude in Page_Load, but that didn't seem to render anything (granted, my understanding of the related plumbing is incomplete).

I tried another one that looked something like this:

<script language="javascript" src='<%= ResolveClientUrl("~/js/ddnmenu.js") %>' type="text/javascript"></script>

...But that throws an exception: The Controls collection cannot be modified because the control contains code blocks.

Working (but somewhat fugly) Code

So, what I ended up going with is a Literal control in the Head where I render the appropriate Html:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Me.SetupLiteralScriptsTag()
End Sub

Private Sub SetupLiteralScriptsTag()
    'Build the script tags to import our JavaScript
    Dim Builder As New StringBuilder

    Builder.AppendLine(String.Format("<script type=""text/javascript"" src=""{0}""""></script>", ResolveClientUrl("~/js/jquery-1.3.2.min.js")))
    Builder.AppendLine(String.Format("<script type=""text/javascript"" src=""{0}""""></script>", ResolveClientUrl("~/js/jquery.corners.min.js")))
    Builder.AppendLine(String.Format("<script type=""text/javascript"" src=""{0}""""></script>", ResolveClientUrl("~/js/bg.pos.js")))
    Builder.AppendLine(String.Format("<script type=""text/javascript"" src=""{0}""""></script>", ResolveClientUrl("~/js/moonstone.js")))

    Me.LiteralScriptTags.Text = Builder.ToString
End Sub

This works, but I'm not on fire about it since it seems like a bit too much of a workaround for what must be an extremely common problem. Is there a better way?

like image 808
Brian MacKay Avatar asked Jun 30 '09 14:06

Brian MacKay


2 Answers

You could add a scriptmanager to the master page and include the javascript files via that:

<asp:ScriptManager ...>
  <Scripts>
    <asp:ScriptReference Path="~/js/ddnmenu.js" />
  </Scripts>
</asp:ScriptManager>

Another advantage of that approach is that you can then add a ScriptManagerProxy control to your content pages (and user controls) to include any additional scripts.

Some third-party replacements for ASP:ScriptManager (e.g. from telerik's RadControls suite or from the Ajax control toolkit) offer even more features, such as merging all included java script files into one file (thus reducing the number of required HTTP requests to load a page).

Edit: using a ScriptManager has some other advantages e.g. you can send debug or release versions of your scripts to the browser, or culture-dependent scripts, etc. etc. Have a look at this page in MSDN for an overview.

like image 168
M4N Avatar answered Sep 23 '22 01:09

M4N


I use app relative syntax everywhere. It does have the drawback that if you change app name/path, then you have alot of work to do updating all of your URL's.

<script language="javascript" src="/MyAppName/Includes/MyJavascriptFile.js">

or if you were working on the root app, then:

<script language="javascript" src="/Includes/MyJavascriptFile.js">

like image 40
Paul Prewett Avatar answered Sep 25 '22 01:09

Paul Prewett