I am wondering what the best practice is for including javascript files inside partial views. Once rendered this will end up as a js include tag in the middle of my page\'s
Today I've created my own solution which fits the bill perfectly. Whether it is good design or not, is for you all to decide but thought I should share either way!
Below is my HtmlExtensions class which allows you to do this in your masterpage:
<%=Html.RenderJScripts() %>
My HtmlExtensions class:
public static class HtmlExtensions
{
private const string JSCRIPT_VIEWDATA = "__js";
#region Javascript Inclusions
public static void JScript(this HtmlHelper html, string scriptLocation)
{
html.JScript(scriptLocation, string.Empty);
}
public static void JScript(this HtmlHelper html, string scriptLocationDebug, string scriptLocationRelease)
{
if (string.IsNullOrEmpty(scriptLocationDebug))
throw new ArgumentNullException("fileName");
string jsTag = "<script type=\"text/javascript\" src=\"{0}\"></script>";
#if DEBUG
jsTag = string.Format(jsTag, scriptLocationDebug);
#else
jsTag = string.Format(jsTag, !string.IsNullOrEmpty(scriptLocationRelease) ? scriptLocationRelease : scriptLocationDebug);
#endif
registerJScript(html, jsTag);
}
public static MvcHtmlString RenderJScripts(this HtmlHelper html)
{
List<string> jscripts = html.ViewContext.TempData[JSCRIPT_VIEWDATA] as List<string>;
string result = string.Empty; ;
if(jscripts != null)
{
result = string.Join("\r\n", jscripts);
}
return MvcHtmlString.Create(result);
}
private static void registerJScript(HtmlHelper html, string jsTag)
{
List<string> jscripts = html.ViewContext.TempData[JSCRIPT_VIEWDATA] as List<string>;
if(jscripts == null) jscripts = new List<string>();
if(!jscripts.Contains(jsTag))
jscripts.Add(jsTag);
html.ViewContext.TempData[JSCRIPT_VIEWDATA] = jscripts;
}
#endregion
}
What is going on?
The class above will extend the HtmlHelper with methods to add javascript links to a collection that is being stored by the HtmlHelper.ViewContext.TempData
collection. At the end of the masterpage I put the <%=Html.RenderJScripts() %>
which will loop the jscripts collection inside the HtmlHelper.ViewContext.TempData
and render these to the output.
There is a downside however,.. You have to ensure that you don't render the scripts before you've added them. If you'd want to do this for css links for example, it wouldn't work because you have to place these in the <head>
tag of your page and the htmlhelper would render the output before you've even added a link.
The preferred approach is to put scripts at the bottom, however, if you can't avoid that then it's reasonable to put them in the middle.
Browsers usually load the various page elements in parallel, however, while the browser is downloading the Javascript file, it won't download any other page elements in parallel until the Javascript is done downloading. This means that your images and what not will have to wait so it's generally considered better to move scripts at the bottom but if your script is small then I wouldn't worry about it.
The designers of MVC went through a lot of trouble to prevent us from using code-behinds, but by creating a file named <viewname>.aspx.cs and modify the inherits attribute of the aspx page accordingly, it is still possible to get them.
I'd say, the best place to put the include would be in the Page_Load handler in the codebehind (using Page.ClientScript.RegisterClientScriptInclude).