Mike Kantor
Mike Kantor

Reputation: 1454

Rendering fields in ASP.NET Razor view with configurable order

I need to allow customers to specify which fields will be drawn in which order, from among a fixed set of fields (address, home phone, SSN, first name, etc. etc.)

What is the best practice for this? I feel like an HTML helper method like "DrawField" is appropriate, but can I use helpers like Html.EditorFor in the body of an HTML helper method? When modelstate has errors and I redisplay the form, will the submitted values and errors be populated?

The "safest" approach seems to be an ugly big loop:

foreach( Field f in FieldList)
{
   if(f.Key == FieldKey.FirstName)
   {
       @Html.LabelFor(model => model.FirstName, StringResource("firstNameLabel"))
       @Html.EditorFor(model => model.FirstName)
       @Html.ValidationMessageFor(model => model.FirstName)
       <br />
   }

   if(f.Key == FieldKey.LastName)
   {
      ......
   }
}

There's gotta be a better way!

Upvotes: 1

Views: 527

Answers (2)

VJAI
VJAI

Reputation: 32768

Although I haven't tried you can try by creating a custom editor / display templates for the Model that takes care of ordering the fields.

To get a basic idea about model templates check this link http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html

UPDATE:

I've tried a simple example. We have a Person model and I want to control the order in which the FirstName and LastName are displayed.

public class Person
{
[Required(ErrorMessage = "The field is required")]
[Display(Name = "First Name:")]
public string FirstName { get; set; }

[Required(ErrorMessage = "The field is required")]
[Display(Name = "Last Name:")]
public string LastName { get; set; }
}

Create a custom editor template Person.cshtml and place it in the Views/Shared folder. So whenever you call the EditorFor method for Person this template will be used for rendering. For simplicity I'm passing the order in which they have to displayed as an array of fields through ViewBag.

@model RazorAndJson.Models.Person
@{
  var fields = ViewBag.FieldsOrder != null 
  ? ViewBag.FieldsOrder 
  : new[] { "FirstName", "LastName" };
}
@foreach(string field in fields)
{
    <p>
         @Html.Label(field)
         @Html.Editor(field)
         @Html.ValidationMessage(field)
    </p>
}

Upvotes: 0

TGH
TGH

Reputation: 39268

Since the list of fields is fixed I would just order it in the controller and just have n regions in the view that will render the fields in the order they arrive in the model. I would structure the model so that it contains a list of the same object, but the content will be different for each one (First name, last name etc) .You can add whatever meta data you need to your model

@Html.LabelFor(model => model.Items[0].Prop, StringResource(model.Items[0].PropName))
@Html.EditorFor(model => model.Items[0].Prop)

......

That way you don't need any conditionals or loops. It's instead n generic regions driven by the data

Upvotes: 1

Related Questions