Art Of Programming

musings by Dmytrii Nagirniak

NHAML – Scripts and Styles, Code Block

Another useful tip for NHAML users that I came up with. I am assuming the site with following technical description:
  1. Every page has common CSS.
  2. Every page has common scripts.
  3. Some page may include up to 2 additional CSS files.
  4. Some pages may include up to 2 additional JS files.
  5. Soma pages may include Google Maps Script.
  6. Some pages may include some of the above based on conditions.
Having these I want to make it as easy as it can be. With WebForms view engine it is not really problematic but it is too verbose. It means more code, more time spent more errors.
But with NHAML it makes it a breath.
Satisfying requirements 1 and 2 i not a problem at all. This is not a problem with WebForms as well. Just including those files in the master page.
What about other? Well, easy. Here is whet i write to satisfy 3 and 4.
^ css = ""
^ script = ""
%h2 Product Details

OR
^ css = "another"
^ script = "another"
%h2 Product Details


What happens here? By using empty string I declare that I want to include the script/css from the default location with default name for the given controller. This is convenient and conventional. This way I enforce that the assets (JS, CSS) are not going to be mixed with views or something else.
In first example I just say “Hey! I need CSS and Script for current controller!”.
In second example I say  “Hey! I need CSS and Script for current controller with name another!”.
You don’t care how and where they will be included. You just tell what you need. That’s it.
This is how we can include 2 script and 2 CSSs:
^ css = ""
^ script = ""
^ csss = "another"
^ scripts = "another"

Ok. Let’s go to 5. The idea is the same but much more “typed”:
^ needMap = true
^ script = "map-integration"
Can it be any easier? We say here: “Mate, I need map on this page. Also don’t forget to give me script that integrates the map with my page.”.

Ok. Now we came to the last point – 6. This is freaking easy as well:
- if (Model.CanEdit)
  ^ script = ""
  ^ css = ""
  ^ needMap = true
  ^ script2 = "map-integration"
We tell here: “If current user can edit this page then please add default script and css for the controller, include map and integration script for it.”
And the possibilities to play with it are unlimited. How does this magic happen?
All is defined in the NHAML “master page” which is called layout. And here it is:
^ string css = null;
^ string css2 = null;
^ string script = null;
^ string script2 = null;
^ bool needMaps = false;
%html{xmlns="http://www.w3.org/1999/xhtml"}
  %head
    != Html.Content().EmitCommonStyles()
    != css==null ? null : Html.Content().EmitCss(css)
    != css2==null ? null : Html.Content().EmitCss(css2)
    != needMaps ? "<script type='text/javascript' src='http://maps.google.com/maps/api/js?sensor=false'></script>" : null

    != Html.Content().EmitCommonScripts()    
    != script==null ? null : Html.Content().EmitScript(script)
    != script2==null ? null : Html.Content().EmitScript(script2)
    
  %body  

I don’t want to explain this – go figure. This is easy as well… Or… ok. in 2 words:
  1. We define .NET variable in the layout using “^” symbol.
  2. The variables defined using “^” are accessible in any page.
  3. There are 2 types of code blocks in NHAML:
    1. starts with “-” - evaluates in its own scope (for simplicity let’s say its scope of page of another block);
    2. starts with “^” – evaluates in the global scope AND before all other scoped blocks (eg: “-”).
Thanks to Simon for explaining this.
Exercise for you: make the layout to satisfy these requirements:
  1. Some pages may have page title (the one shown in the browser): “Action – Area – SiteName”
  2. Some pages may have page title: “Action – SiteName” or “Area – SiteName”.
  3. If neither Action nor Area are provided site will have in its title “SiteName”.
  4. A page should not be required to specify anything if it doesn’t need to. So if a page doesn’t provide neither Action nor Area it should not have any code at all to handle this.
Can you do that? [Tip: NHAML supports extension methods as well.]

Comments