I have been knocking this post around in my head for a couple of days now. It all started when I read this great post about how to use the jQuery DatePicker widget with ASP.NET MVC. In that post, the Stuart Leeks “hard-wires” the date format to be the UK format for the date-picker and leaves it to the reader to dynamically set that format as an exercise.
I recall my times in Webforms where the task of rendering ClientIDs for Server controls in Javascript was quite challenging. A lot of people wrote horrible code in their mark-up like:
'<%= SecurityCheckCompleteCheckBox.ClientID %>'
Ugh, grotesque. (I can’t count the number of dodgy forum posts which put that syntax forward as a solution). Guys with more enterprise experience wrote elegant code like this.
In MVC, it is a lot easier to accomplish this, given the fact that HTML ids are not generated for you by the ASP.NET runtime. But, we still may come up against a situation whereby we want to use a variable in a javascript file which you want to dynamically set at runtime.
For example, take the date format for the DatePicker in the blog post referred to above. There, the javascipt file has some script like this:
$('.date').each(function () {
var minDate = getDateYymmdd($(this).data("val-rangedate-min"));
var maxDate = getDateYymmdd($(this).data("val-rangedate-max"));
$(this).datepicker({
dateFormat: "dd/mm/yy", // UK format hard-coded
minDate: minDate,
maxDate: maxDate
});
});
The problem to solve is that you want to use a dynamically generated javascript variable so that the code looks more like this:
$('.date').each(function () {
var minDate = getDateYymmdd($(this).data("val-rangedate-min"));
var maxDate = getDateYymmdd($(this).data("val-rangedate-max"));
$(this).datepicker({
dateFormat: SvrSideVariables.DateFormat, // format set server-side
minDate: minDate,
maxDate: maxDate
});
});
As you are aware, you can’t write any kind of C#/server-side code inside a javascript file. And although you can do it in a script tag in the markup, script tags containing javascript content are evil, unless dynamically generated. The separation of presentation from behaviour requires that there be no javascript in the markup, unless it is just a script element pointing to an external javascript file.
What follows is a very basic solution to this problem. There are many approaches one could take to attacking this problem.
Lets set the dateformat variable in the web.config file, so we can change it without having to recompile.
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
<add key="DateFormat" value="dd/mm/yy"/>
</appSettings>
Then, we’ll just use a simple custom HtmlHelper to render that variable in a script tag, which we will add to the head section of our document:
public static MvcHtmlString CreateServerSideVariables(this HtmlHelper helper, string variable)
{
// Create tag builder
var builder = new TagBuilder("script");
// Add attributes
builder.MergeAttribute("type", "text/javascript");
// We want a namespace, because as the great Douglas Crockford said, the Global namespace is eeevil.
builder.InnerHtml = "if(typeof SvrSideVariables == 'undefined') var SvrSideVariables = { }; SvrSideVariables.DateFormat = '" + variable + "';";
// Render tag.
return MvcHtmlString.Create(builder.ToString(TagRenderMode.Normal));
}
}
Such a script tag is fine, because it keeps the markup which you have to maintain clean (no mixing of behaviour and presentation) and it is done dynamically at run-time. Make sure you add that element before your custom script, so the variable “SvrSideVariables.DateFormat” will be available for use by your custom script which uses it to set the date format for your datepicker.
Finally, use the helper (in the Edit.cshtml file):
@section ServerSideVariables{
@Html.CreateServerSideVariables(ConfigurationManager.AppSettings["DateFormat"])
}
And of course in the _Layout.cshtml:
@RenderSection("ServerSideVariables", false)
That’s one of several approaches.
Get the code, which just augments the code from the original article: