A Bit About Spark

In my last post I installed and configured Spark as an alternative view engine for ASP.NET MVC. Before we do anything else with it though, we need to understand a little of the syntax.

The Spark View Page

First of all, a Spark page looks much like an HTML page. It supports HTML tags as you’d expect but allows you to intersperse code and do some other clever things very succinctly. So, for example, the following is a valid Spark view page:

 <p>Hello World.</p>

It’s not a very good view page – it doesn’t have a valid structure or DOCTYPE for example – but it is a view page.

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
  <title></title>
</head>
<body>
  <p>Hello World.</p>
</body>
</html>

Is better.

Adding Code

How about we want to add some code?

 <p>Hello ${Context.User.Identity.Name}.</p>

Would greet the (authenticated) user. The ${} syntax executes the embedded code and generates output. This output is automatically HTML encoded (set in configuration). If you want to bypass HTML encoding use !{} instead. So, for example, to use an HTML helper method we would use:

 <p>Hello ${Context.User.Identity.Name}.</p>
<div>!{ Html.ActionLink("Log On", "LogOn", "Account") }</div>

Conditionals

Conditional statements take the form

 <if condition='Some Condition'>
  Do Something
</if>
<else>
  Do Something Else
</else>

Variables

It’s possible to create local and global variables (useful for sharing data across view, master and partial views).

 <global type='string' Title='"Title"'/>

And you can then set them using

 <set Title="'Find a Dinner (Spark)'" />

Accessing ViewData

You have access to the ViewData. You can use ${ViewData["key"]} but there is a better way:

 <viewdata 
  Caption="string" 
  Products="System.Collections.Generic.IList[[MyApp.Models.Product]]"/>

This gives me strongly-types access to two objects stored in ViewData, Caption (of type string) and Products (of type IList<MyApp.Models.Product>. The [[]] syntax is used in the markup to avoid the editor trying to add matching closing elements when you’re trying to indicate a generic type.

If I have a strongly-typed Model, I can do this instead:

 <viewdata model="NerdDinner.Helpers.PaginatedList[[NerdDinner.Models.Dinner]]" />

And I then have strongly-typed access to my Model which is a PaginatedList of Dinners (see Nerd Dinner for more info – this is the model type used for Dinners/Index view).

Looping / Enumerating Collections

There is then a very neat syntax for enumerating a collection – along the lines of:

 <li each="var dinner in Model">     
    !{ Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) }
    on 
    !{ Html.Encode(dinner.EventDate.ToShortDateString()) }
    @
    !{ Html.Encode(dinner.EventDate.ToShortTimeString()) }
</li>

Which essentially says for each dinner in the Model (collection of dinners) create me an <li> element of this shape.

Masterpages and Partial Views

We haven’t yet touched on how to create the standardised look and feel that a Web Forms masterpage can create and how to manage re-usable templates (the equivalent of partial views in the Web Forms view engine). Good news! Both are possible…

For master pages (master-layouts in Spark), there a number of options, I managed to get away with the easiest which is simply to create an Application.spark file in the Shared views folder. This is the equivalent of your Web Forms master page. This master-layout file can reference “named content” which happens to be the result of rendering the view page itself. So for example, the master-layout might contain something like:

 <div id="main">
    <use content="MainContent"/>
</div>

And the view page would be:

 <content name="MainContent">
  <div>Hello World!</div>
</content>

When the view is rendered, the resulting markup is “injected” into the master-layout at the appropriate place.

Partial views are similar and again there a number of options but if you follow the right convention, you can use a syntax like this in your view:

 <div id="logindisplay">
  <LoginStatus />
</div>

And the the LoginStatus partial view will be rendered inside the <div> tags. The convention is to name your partial view file starting with an underscore, so in the case _LoginStatus.spark, and place it in the shared directory or the view directory for the controller.

In the next post I’ll go through the equivalent Spark code I used to replace a few of the pages in the Nerd Dinner site.