ASP.NET, MVC3, Razor and adding scripts where they supposed to go

By Kenneth 'RabidDog' Clark at August 22, 2011 20:12
Filed Under: C#, Code, JavaScript, Work

I was always under the impression that the HEAD of an HTML document contained the SCRIPT tags. Call me old fashioned but I actually quiet like it that way.

 

Then I came across a discussion at http://stackoverflow.com/questions/1213281/does-javascript-have-to-be-in-the-head-tags concerning this very thing. Some say HEAD, some say BODY and some say WHERE_EVER_YOU_WANT. I then went and confirmed the HEAD and BODY issue at http://www.w3.org/TR/html4/interact/scripts.html

 

I can see validity in the arguments but with the advent of the unobtrusive JavaScript model I am beginning to wonder if arguments like this are really valid any longer. I also question whether being able to see the page before being able to use it is such a good idea. I personally would prefer the user is not able to see anything till the code to assist them has loaded. Again with the unobtrusive JavaScript stuff, my argument is also flawed.

 

Either way, I decided I wanted a mechanism where I could add the path to a collection and it would be inserted into the page in a central location, top or bottom, HEAD or BODY.

 

So I had a look at the ViewBag now offered in MVC 3 and decided it would be the best place to have a collection like this. Seeing as it is dynamic and available on all pages it made the most sense. I didn’t want to have to go and create a store to store the collection in and then query it before rendering, I just wanted it to work so below is what I came up with:

   1: //Inside the view page
   2: @{
   3:     ViewBag.Title = "MyPage";
   4:     ViewBag.Scripts = new List<String> { "Pages/MyPage.js" };
   5: }

Then in the master or layout page you can quiet easily do this:

   1: <head>
   2:     <title>@ViewBag.Title</title>
   3:     <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
   4:     <script src="@Url.Content("~/Scripts/jquery-1.6.2.min.js")" type="text/javascript"></script>
   1:  
   2:     @{
   3:         if (ViewBag.Scripts != null) {
   4:             foreach (var script in ViewBag.Scripts) {
   5:         <script src="@Url.Content("~/Scripts/" + @script)" type="text/javascript">
</script>
   5:             }
   6:         }
   7:     }
   8: </head>

This neatly renders the the script tags into the HEAD section (where I wanted it).

 

I then went and created an html helper to do this so I could use without all the verbose checking being embedded in the view/layout page.

   1: using System.Collections.Generic;
   2: using System.Text;
   3: using System.Web.Mvc;
   4:  
   5: namespace System.Web.Helpers {
   6:     public static class HtmlHelper {
   7:  
   8:         const string ScriptTag = "<script src=\"{0}\" type=\"text/javascript\"></script>";
   9:         private const string PathPrefix = "~/Scripts/{0}";
  10:  
  11:         /// <summary>
  12:         /// Inserts the scripts. If using a viewbag remember to cast the input property
  13:         /// </summary>
  14:         /// <param name="html">The HTML.</param>
  15:         /// <param name="scripts">The scripts.</param>
  16:         /// <param name="urlHelper">The URL helper.</param>
  17:         /// <returns></returns>
  18:         public static IHtmlString InsertScripts(this System.Web.Mvc.HtmlHelper html, IList<String> scripts, UrlHelper urlHelper) {
  19:  
  20:             if (scripts == null)
  21:                 return new HtmlString(String.Empty);
  22:  
  23:             var output = new StringBuilder();
  24:  
  25:  
  26:             foreach (var script in scripts) {
  27:                 output.AppendFormat(ScriptTag, urlHelper.Content(String.Format(PathPrefix, script)));
  28:             }
  29:  
  30:             return html.Raw(output.ToString());
  31:         }
  32:     }
  33: }

Which means the call in the view or layout page is reduced to

   1: <head>
   2:     <title>@ViewBag.Title</title>
   3:     <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
   4:     <script src="@Url.Content("~/Scripts/jquery-1.6.2.min.js")" type="text/javascript"></script>
   5:     @Html.InsertScripts((IList<String>)ViewBag.Scripts, Url);
   6: </head>

 

Nice and clean (well kinda)

Comments (2) -

9/4/2011 4:14:59 PM #

Wow! Amazing post, it was very informative! Thank you for creating this, I learned alot. I found this blog using Google... I really like google! Have a great day!

Nannie Landford United States | Reply

10/6/2011 5:53:36 PM #

Amazing topic, wish I could come up with news like that for my page, hahaha.

Watch 24 United States | Reply

Add comment




  Country flag
biuquote
  • Comment
  • Preview
Loading








I am South African. Always have been always will be. I love my country. I love my wife and two children.


I also really enjoy solving problems. I currently work as a Software Architect exploring new solutions for business problems. Having been round the block a few times I enjoy showing new developers how best to solve problems, how to find answers and how to approach solution development.


In my spare time I enjoy riding my super bike, training in Systema and horsing around with my family.


Month List

Visitors

Twitter Feed

21. May 10:15
Still can't believe that they used american actors in Invictus. Just doesn't fit!

17. May 17:12
@UnexpectedPippa only 3? "Don't touch me on my studio!"

17. May 17:12
@SaartjieJoan if you look around you might see many forks hanging out of eye sockets

17. May 17:09
@SaartjieJoan That truly is amazing HAHAHAHA!