A long time ago, in a paragraph far, far away (at the beginning of this chapter, actually), you were building a form for a customer to submit the information needed to process an order. You did this using the EditorForModel HTML helper, and the form wasn't turning out quite how you expected. Figure 6.8 should help to refresh your memory.
Two problems are evident in the screenshot:
The path to resolving these problems also lies in the DataAnnotations namespace.
Like the validation attributes you looked at previously, a model metadata provider picks up the following display (and edit) annotations and makes their information available to HTML helpers and other components in the MVC run time. The HTML helpers use any available metadata to change the characteristics of a display and edit UI for a model.
The Display attribute sets the friendly display name for a model property. You can use the Display attribute to fix the label for the FirstName field:
[Required] [StringLength(160, MinimumLength=3)] [Display(Name="First Name")] public string FirstName { get; set; }
With the attribute in place, your view renders as shown in Figure 6.9.
In addition to the name, the Display attribute enables you to control the order in which properties will appear in the UI. For example, to control the placement of the LastName and FirstName editors, you can use the following code:
[Required] [StringLength(160)] [Display(Name="Last Name", Order=15001)] [MaxWords(10, ErrorMessage="There are too many words in {0}")] public string LastName { get; set; } [Required] [StringLength(160, MinimumLength=3)] [Display(Name="First Name", Order=15000)] public string FirstName { get; set; }
Assuming no other properties in the Order model have a Display attribute, the last two fields in the form should be FirstName, then LastName. The default value for Order is 10,000, and fields appear in ascending order.
The ScaffoldColumn attribute hides a property from HTML helpers such as EditorForModel and DisplayForModel:
[ScaffoldColumn(false)] public string Username { get; set; }
With the attribute in place, EditorForModel will no longer display an input or label for the Username field. Note, however, the model binder might still try to move a value into the Username property if it sees a matching value in the request. You can read more about this scenario (called over-posting) in Chapter 7.
The two attributes you've looked at so far can fix everything you need for the order form, but take a look at the rest of the annotations you can use with ASP.NET MVC 4.
The DisplayFormat attribute handles various formatting options for a property via named parameters. You can provide alternate text for display when the property contains a null value, and turn off HTML encoding for properties containing markup. You can also specify a data format string for the run time to apply to the property value. In the following code you format the Total property of a model as a currency value:
[DisplayFormat(ApplyFormatInEditMode=true, DataFormatString="{0:c}")] public decimal Total { get; set; }
The ApplyFormatInEditMode parameter is false by default, so if you want the Total value formatted into a form input, you need to set ApplyFormatInEditMode to true. For example, if the Total decimal property of a model were set to 12.1, you'd see the output in the view shown in Figure 6.10.
One reason ApplyFormatInEditMode is false by default is because the MVC model binder might not like to parse a value formatted for display. In this example, the model binder will fail to parse the price value during postback because of the currency symbol in the field, so you should leave ApplyFormatInEditModel as false.
Place the ReadOnly attribute on a property if you want to make sure the default model binder does not set the property with a new value from the request:
[ReadOnly(true)] public decimal Total { get; set; }
Note the EditorForModel helper will still display an enabled input for the property, so only the model binder respects the ReadOnly attribute.
The DataType attribute enables you to provide the run time with information about the specific purpose of a property. For example, a property of type string can fill a variety of scenarios — it might hold an e-mail address, a URL, or a password. The DataType attribute covers all of these scenarios. If you look at the Music Store's model for account logon, for example, you'll find the following:
[Required] [DataType(DataType.Password)] [Display(Name="Password")] public string Password { get; set; }
For a DataType of Password, the HTML editor helpers in ASP.NET MVC will render an input element with a type attribute set to password. In the browser, this means you won't see characters appear onscreen when typing a password (see Figure 6.11).
Other data types include Currency, Date, Time, and MultilineText.
The UIHint attribute gives the ASP.NET MVC run time the name of a template to use when rendering output with the templated helpers (like DisplayFor and EditorFor). You can define your own template helpers to override the default MVC behavior, and you'll look at custom templates in Chapter 16.
The HiddenInput attribute lives in the System.Web.Mvc namespace and tells the run time to render an input element with a type of hidden. Hidden inputs are a great way to keep information in a form so the browser will send the data back to the server, but the user won't be able to see or edit the data (although a malicious user could change submitted form values to change the input value, so don't consider the attribute as foolproof).