Opinionated Input Builders for ASP.Net MVC – Part 5 the Required input

The Required Field Indicator

The Required Field Indicator is a property which allows the UI to indicate that a field is required.  The example below shows that an asterisk could be used to indicated the field is required. This could be used to apply a css class to the Label which could change the color or bold the label.  The possibilities for how you turn this property into a compelling user interface is endless. The important point to know is that there are different approaches to decide how this could be set.

image

 

Model Approach

Here is an example of using a DataAnnotations Required attribute as a way to indicate the field is required.  I like this approach since this attribute can be used with a Model Binder to perform Model Validation using model state.   This model binder will be provided in the ASP.Net MVC 2.0 release so I included this as a way to get synergy with existing features of the MVC framework.

image

I have received a lot of feed back that people feel marking your model with attributes pollutes the model.  I disagree with this because the models that I use are View Models not my Domain entities which represent my business object which will be stored into my database.  The Models that I would decorate with validation attributes would be used for one specific MVC View.  The model would represent the fields needed to create the User Interface view. 

Fluent Approach

An alternative approach to using attributes would  be to use a Fluent method as shown below. I dislike this approach as it does not work with my preferred way of performing data type validation using the MVC Model Binder. in the framework. I would be more likely to use the fluent methods for the Label or PartialView selection, but I would not use it for the Required indicator because it would mean I am duplicating how I identify a required property on my Model.

image

The View markup

Here is an example of how the Required property is used in the Field.Master master page.  As I wrote earlier, this could be used to add a css class to the html markup.

image

Your own convention

The framework uses a convention to determine if a Model property is required.  By implementing your own PropertyIsRequiredConvention you could make all Properties with the name Name & Description required or  whatever makes sense for the type of application that you are creating. It could be Username or email if you are creating a consumer facing website the possibilities are endless. But at the end of the day you can have your own convention.

image

Here is the implementation of my Default Convention for Property Is Required, it is simple and to the point.  I could see implementing some sort of Chain of Responsibility pattern here and in the other conventions to have some consistency to your User Interface.

image

Thoughts… opinions..?

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Eric Hexter

I am the CTO for QuarterSpot. I (co)Founded MvcContrib, Should, Solution Factory, and Pstrami open source projects. I have co-authored MVC 2 in Action, MVC3 in Action, and MVC 4 in Action. I co-founded online events like mvcConf, aspConf, and Community for MVC. I am also a Microsoft MVP in ASP.Net.
This entry was posted in .Net, Asp.Net, Asp.Net MVC, c#, CoC, mvccontrib. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.johnnyhall.co.uk/ Johnny Hall

    Hi. Good work, looking forward to it making it into MvcContrib.

    What do you think of integration with xVal? Have you looked at this, and what might be involved?

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    Hey Eric,

    One thing you might consider is getting rid of all prepositions. Instead of “UsingPartial”, just “Partial”. Instead of “AsRequired”, just “Required”. Instead of “WithLabel”, just “Label”. It’s easier to scan with just the adjectives, the other words are just fluff.

  • http://www.lostechies.com/members/erichexter/default.aspx erichexter

    @johnny I think making this work with xVal should not require any changes. xVal works by providing client side code for the entire model, while the input helpers work at the Model Property level. so these should work together really well. There is a feature that will generate the entire form for the Model and that will require modifying the Model Master Page but I have not worked out the details yet.

    @bogardj fair enough… I guess I was on the Fluent bandwagon and thought if I was to add a fluent interface than I should add the prepositions to the interface. I think that the fluent part of this API should be built as Extension Methods that way it is pretty easy to ditch one syntax for another. I can provide a prescriptive way but if a project is using another framework that implements a set of fluent interfaces it would be trivial for them to make wrapper so that they get consistency around all of their frameworks…

  • benhyrman

    To be honest, I was a little put off by having to decorate the model. Then, I realized it’s perfectly valid and a great addition to the ViewModel. Then I started to worry that I might need more ViewModels. Then I realized that this, some extra ViewModels, and AutoMapper would all work together to make life pretty painless.

  • http://www.lostechies.com/members/erichexter/default.aspx erichexter

    @benhyrman You hit the nail on the head. Automapper and the input builders work together like peanut butter and jelly. We ( Headspring) uses both together on our projects. It does work really well.

  • http://16randombytes.blogspot.com Bill Barry

    Having done something very similar to this, but for webforms[1] I have come to think that you really need to do this one level out:
    < %=Html.ValidationSummary()%>
    This sample demonstrates …
    < % Html.Form(“save”, “home”); %>

    With overrides like:

    < % Html.Form(“save”,”home”)
    .Override(c=>c.TimeStamp, element =>
    element.Partial(“DatePicker”).Sorted(2.5))
    .Override(c=>c.Enum, element => element.Required())
    .Override(c=>c.Html, element =>
    element.Label(“Label overridden from the view”));%>

    or:

    < % Html.Form(“save”,”home”)
    .Override(c=>c.TimeStamp)
    .Partial(“DatePicker”).Sorted(2.5).End()
    .Override(c=>c.Enum)
    .Required().End()
    .Override(c=>c.Html)
    .Label(“Label overridden from the view”).End();%>

    (I don’t know which syntax would be better)

    The point being that if you use the model for more than one form (say Customer, Salesperson, Manager and Admin each get only slight variations of the same form, but from different views) you do not repeat the stuff that is the same for all of them. Then when your model expands, you don’t need to alter the forms.

    1:
    In webforms I am adding the following to get a model designed form:
    FormPlaceHolder.Controls.Add(FormFor.Create());

    this builds a full form complete with Telerik inputs and validation client side for MyModel.

  • http://www.lostechies.com/members/erichexter/default.aspx erichexter

    @Bill Barry I would really stay away from trying to reuse Model across forms(views). It is because of that reuse that you would need to ability to do more inline exceptions inside the view. If the Model has exactly what is needed for the form(view) than you can really rely on the conventions to keep the code inside the view to a minimum.

    I still have a lot of work to do to figure out how you would override an entire set of partials.. almost like a theme. But I am sure we will work through that.

  • http://16randombytes.blogspot.com/ Bill Barry

    I agree, which is why I would use just the first bit from my example. Unfortunately not everybody thinks like I do.
    The part I am talking about to suggest that this is all that should be done for 90% of all forms:
    < %=Html.ValidationSummary()%>
    This sample demonstrates …
    < % Html.Form(“save”, “home”); %>

    perhaps with default values being provided:
    < % Html.Form("save", "home", Model); %>

  • http://www.lostechies.com/members/erichexter/default.aspx erichexter

    @Bill Barry If you look in the source code I have one view which has the following form < %=Html.InputForm("Home","Save")%> The Model does not have to be specified as it can be obtained from the HtmlHelper. I am not sure what part of the series I will get to that one but I do have it working.. It was a natural progression once the other pieces of the builder came together.

  • Tad

    What are the performance implications of that opinionated helpers?

  • http://www.lostechies.com/members/erichexter/default.aspx erichexter

    @Tad there has been zero performance work done on this so far. As they stand i am sure that their are some areas that would not scale very well under high load. I still need to address that but I am certain that with some profiling the any performance problems could be worked through so that the gain in productivity and consistency of your application will far out weigh the performance penalty you pay for using this type of control selection.

    Under the hood the code goes through the lambda expressions and than uses reflection to get the value of the property from the model. I know there are performance penalties with this type of access. I also know that their are a few different ways to overcome this through IL generation and caching of compiled expressions. So in the long term I am not worried because there are some well defined ways to deal with those issues. But until I do the performance testing I do not want to start optimizing any of the code.

  • http://www.overridethis.com Roberto Hernandez

    You are missing the classical DropDownList using referencial data from a data store. I know that it can be done using the partial views scenario, but I still would love to see a good sample on how to implement it and how it affects the design of your ViewModel.

    Regards,

    Roberto.-

  • http://www.lostechies.com/members/erichexter/default.aspx erichexter

    @Roberto, This is on my list to implement. I could see the convention calling into a chain of responsibilities provider that could decide to pull the appropriate data from a repository. that being said I do need to get that example put in so that it is clear how to extend it and get some feedback to improve on the design.

  • http://www.hanselman.com Scott Hanselman

    Wouldn’t you then need to create or extend the DefaultModelBinder to make sure that the length, required, and other attributes on the ViewModel are respected on the way IN to a method after a POST?

  • http://www.lostechies.com/members/erichexter/default.aspx erichexter

    @Scott in this sample I am actually using the DataAnnotations Model Binder and the preview of the DataAnnotations dll from the Mvc Release on codeplex. I wanted to demonstrate that this method of implementing the Opinions lets the developer choose their approach and use this framework to plug in an attribute based approach or a code based approach. I think that which ever approach is used it has to be tied into the validation and model binder.

  • Sean

    How would the attribute-based approach extend to situations where you wanted to make required|NOTrequired configurable based on the user role, or perhaps even at an application instance level?

  • http://www.lostechies.com/members/erichexter/default.aspx erichexter

    @sean, you would need to implement your own convention and wire it in at application start up. The convention would use service location to create a class that can look into web context and determine the user of the current request and than return the appropriate value.