fredag 5 april 2013

jQuery Validation not working in ASP.NET MVC solution

I was implementing a simple register user form the other day and had some difficulties getting the jQuery Validation framework to work. The view code was really straight forward:
<div data-role="fieldcontain">
    @Html.EditorFor(m => m.UserName)
</div>
<div data-role="fieldcontain">
    @Html.EditorFor(m => m.EmailAddress)
</div>
<div data-role="fieldcontain">
    @Html.EditorFor(m => m.Password)
</div>
<div data-role="fieldcontain">
    @Html.EditorFor(m => m.ConfirmPassword)
</div>
<input type="submit" data-role="button" data-theme="b" value="Register" />

And the model to validate looks like this:
public class RegisterModel
{
    [Required]
    [Display(Name = "User name")]
    public string UserName { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }

    [Required]
    [DataType(DataType.EmailAddress, ErrorMessage = "Invalid Email Address")]
    [Display(Name = "Email")]
    public string EmailAddress { get; set; }
}

When submitting an empty form only the server side validation kicked in. After a few hours of trial-and-error I found out that apparently you have to add a validation message for EVERY field in the form which are about the get validated. Updating my view to this solved my problems:
<div data-role="fieldcontain">
    @Html.EditorFor(m => m.UserName)
    @Html.ValidationMessageFor(m => m.UserName, "*")
</div>
<div data-role="fieldcontain">
    @Html.EditorFor(m => m.EmailAddress)
    @Html.ValidationMessageFor(m => m.EmailAddress, "*")
</div>
<div data-role="fieldcontain">
    @Html.EditorFor(m => m.Password)
    @Html.ValidationMessageFor(m => m.Password, "*")
</div>
<div data-role="fieldcontain">
    @Html.EditorFor(m => m.ConfirmPassword)
    @Html.ValidationMessageFor(m => m.ConfirmPassword, "*")
</div>
<input type="submit" data-role="button" data-theme="b" value="Register" />

Hopefully this blog post will help others in the same situation :)
/Erik

tisdag 15 januari 2013

ASP.NET - Dynamically and programmatically work with System.Web.UI.WebControls.Content controls

In my current project I had a scenario where I wanted to (sometimes) replace/not show content from my ASP.NET Master Page on a particular ASPX-page. One way to do this is of course to create a new master page, add necessary content to it and then programmatically use different master pages depending on some parameters (in my case a query string). I'm not a big fan of this solution since it introduces more complexity to the project in forms of new files.

A cleaner and better way (my opinion!) would be to, sometimes, replace some of the System.Web.UI.WebControls.ContentPlaceHolder controls from my master page with empty content and by this achieving the same goal as with the multiple master pages approach. The problem with this solution is that is seems impossible to work with existing ASP.NET Content controls from code behind. Even if I set IDs to the controls I can't seem to access them from code. I found a simple solution to this by creating a new, empty ITemplate and using the Page.AddContentTemplate function:

public class StandardPage : Page
{
    protected override void OnPreInit(System.EventArgs e)
    {
        // If the param showStripped is submitted we want to hide 
        // header and footer by adding empty content controls overriding 
        // ContentPlaceholders for those areas in the MasterPage
        var showStripped = Request.Params["showStripped"];
        if (!string.IsNullOrEmpty(showStripped))
        {
            AddContentTemplate("cphFacebookScript", new EmptyContent());
            AddContentTemplate("cphHeader", new EmptyContent());
            AddContentTemplate("cphFooter", new EmptyContent());
        }
        base.OnPreInit(e);
    }
}

public class EmptyContent : ITemplate
{
    void ITemplate.InstantiateIn(Control container) { }
}

So when calling the page with the querystring showStripped we will add empty content templates to some of the content placeholders from the master page. Pretty simple, right?! :)