WebForms: Dynamic (or absolute) script tags in MasterPages
Asked Answered
B

5

6

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?

Bake answered 30/6, 2009 at 14:19 Comment(0)
A
3

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">

Alexandra answered 30/6, 2009 at 14:24 Comment(2)
At least the work is minimized in the masterpages scenario. It's amazing that I didn't know you could do it this way... I've been working on web apps for a very long time!Bake
I accepted this one iinstead of M4N's answer since this is the simplest. You can use it without introducing any new concepts to your project... Although I do use ScriptManager for this now.Bake
T
7

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.

Tawnytawnya answered 30/6, 2009 at 14:25 Comment(1)
Then simply accept mine ;-) - no seriously, accept whichever answer helped you the most.Tawnytawnya
A
3

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">

Alexandra answered 30/6, 2009 at 14:24 Comment(2)
At least the work is minimized in the masterpages scenario. It's amazing that I didn't know you could do it this way... I've been working on web apps for a very long time!Bake
I accepted this one iinstead of M4N's answer since this is the simplest. You can use it without introducing any new concepts to your project... Although I do use ScriptManager for this now.Bake
S
2

I use Page.resolveUrl("~/somefile.js");

works like a champ

Superposition answered 30/6, 2009 at 14:28 Comment(0)
D
0

You could reference your script always from the root. IE:

<script language="javascript" src="/scripts/file.js"></script>

Any page in your app would then get the javascript properly.

Also, since you are working with ASP.NET you could make use of the "~" character for providing application based relative paths. See Rick Strahl's article on ASP.NET paths for more info.

Danielledaniels answered 30/6, 2009 at 14:25 Comment(1)
The tilde only works inside of server controls. I would love to use it here though.Bake
D
0

The Controls collection cannot be modified because the control contains code blocks

That error sounds familiar. This page helped when I fumbled my way through this one

Dervish answered 30/6, 2009 at 14:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.