In a recent Asp.Net MVC project i had to set a focus on a specific control, but it wasn’t just a specific control. It was calculate in runtime by some conditions. I didn’t just want to create an extra string property on the viewmodel where i could store the id of the control. Off course this would also work but i wanted something safer than those magic strings.
In one of my previous posts (Where is the ClientID?), i was able to determine the Id that is created by the HtmlHelper to create a textbox, checkbox, …
public static class HtmlHelper
{
public static String GetId<TModel,TProperty>( this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression )
{
return TagBuilder.CreateSanitizedId(ExpressionHelper.GetExpressionText(expression));
}
}
So i created a property called Focus on my ViewModelBase class with the exacte same type, but for the return type of the function i take Object.
public abstract class ViewModelBase<T>
{
public Expression<Func<T,Object>> Focus { get; set; }
}
Then my PersonViewModel inherits from ViewModelBase<T> where T equals the PersonViewModel type. That way i have complete intellisence when i want to set the Focus property.
public class PersonViewModel : ViewModelBase<PersonViewModel>
{
public String Name { get; set; }
public String LastName { get; set; }
}
At the view side, i’ll use the GetId extension method to determine the id off the control i want to set the focus to. I’ll pas the Focus property as parameter for this extension method. Then i’ll use it’s result in a JQuery selector and invoke the .focus() method.
@model ASP.NET_MVC_Set_Focus_ViewModel_Style.Models.PersonViewModel
@{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
@using (Html.BeginForm())
{
<table>
<tr>
<td>
Name
</td>
<td>
@Html.TextBoxFor(m => m.Name)
</td>
</tr>
<tr>
<td>
Lastname
</td>
<td>
@Html.TextBoxFor(m => m.LastName)
</td>
</tr>
</table>
@Html.HiddenFor(m => m.Focus)
<input type="submit" value="ChangeFocus" />
}
<script type="text/javascript">
$(document).ready(function () {
$("#@Html.GetId(Model.Focus)").focus();
});
</script>
At the Controller side, on the HttpGet method, i’ll set the focus on the Name. On the HttpPost method, i’ll set the focus on LastName. That way you’ll see the difference.
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
var personViewModel = new PersonViewModel();
personViewModel.Focus = m => m.Name;
return View(personViewModel);
}
[HttpPost]
public ActionResult Index(PersonViewModel personViewModel)
{
personViewModel.Focus = m => m.LastName;
return View(personViewModel);
}
}
The main advantage is that you don’t have to work with those magic strings. When the property is renamed or removed, i’ll get a compiler error. And your code is cleaner.
This code isn’t rocket science but can be very handy. The solution can be downloaded from here.