Monday, August 22, 2011

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

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 cam across a discussion at http://stackoverflow.com/questions/1213281/does-javascript-have-to-be-in-the-head-tags concerning this very thing. So 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 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 { "Pages/MyPage.js" };



   5: }




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







   1: <head>



   2:     <title>@ViewBag.Titletitle>



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



   9:         private const string PathPrefix = "~/Scripts/{0}";



  10:



  11:         /// 



  12:         /// Inserts the scripts. If using a viewbag remember to cast the input property



  13:         /// 



  14:         /// The HTML.



  15:         /// The scripts.



  16:         /// The URL helper.



  17:         /// 



  18:         public static IHtmlString InsertScripts(this System.Web.Mvc.HtmlHelper html, IList 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.Titletitle>



   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)

No comments:

Post a Comment