Matt
Matt

Reputation: 4752

How do I create an editor template that works with existing data?

I created an editor template to display text boxes included in a form.

    @model WebApplication1.Models.PersonViewModel

<input type="text" class="form-control" name="@ViewData.TemplateInfo.HtmlFieldPrefix" value=""/>

I simply want to include the 'form-control' class in all my input text boxes used to collect data for this model.

public class PersonViewModel
{ 
    [UIHint("_TextFormControl")]
    public string FirstName { get; set; }
    [UIHint("_TextFormControl")]
    public string LastName { get; set; }
    public int Age { get; set; }

}  

This works great when the form starts out blank, however, when I use the template for forms pre-populated with data, like when I want to edit an existing model, I get the error message: "The model item passed into the dictionary is of type 'System.String', but this dictionary requires a model item of type 'WebApplication1.Models.PersonViewModel'."

Here is my controller:

 // GET: /Person/Edit/5
    [HttpGet]
    public ActionResult Edit(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }

        Person person = db.Persons.Find(id);

        if (person == null)
        {
            return HttpNotFound();
        }

        return View(person);
    }

How do I allow this editor to be used with existing data, as well as new forms?

Upvotes: 0

Views: 1850

Answers (1)

user3559349
user3559349

Reputation:

You have created an EditorTemplate for typeof PersonViewModel but your use of [UIHint("_TextFormControl")] applied to typeof string means your passing string to the template, not PersonViewModel. Its unclear exactly what your trying to achieve here but based on your current model, he template needs to be

@model String
@Html.TextBox("") // or @Html.TextBoxFor(m => m)

However this is just the same as using @Html.EditorFor(m => m.FirstName) (or TextBoxFor()) in the view. One reason you might do something like this is generate multiple html elements, for example

@model String
@Html.Label("")
@Html.TextBox("")
@Html.ValidationMessage("")

so that using @Html.EditorFor(m => m.FirstName) in the main view would generate the label, textbox and placeholder for validation messages.

But one of the real benefits of using custom editor templates is when you use them for complex types and want a consistent UI for those types. For example, you can create a template for typeof PersonViewModel. In /Views/Shared/EditorTemplates/PersonViewModel.cshtml (note that the name of the template must match the name of the type)

@model WebApplication1.Models.PersonViewModel
<div>
  @Html.LabelFor(m => m.FirstName)
  @Html.TextBoxFor(m => m.FirstName)
  @Html.ValidationMessageFor(m => m.FirstName)
</div>
<div>
  @Html.LabelFor(m => m.LastName)
  @Html.TextBoxFor(m => m.LastName)
  @Html.ValidationMessageFor(m => m.LastName)
</div>
.... // ditto for other properties of PersonViewModel

Then in the main view

@model WebApplication1.Models.PersonViewModel
@Html.EditorFor(m => m)

This will also work for a collection of PersonViewModel and generate one editor template for each PersonViewModel in the collection

@model IEnumerable<WebApplication1.Models.PersonViewModel>
@Html.EditorFor(m => m)

Similarly, if you had another model that contained a property public PersonViewModel Person { get; set; }, you can use @Html.EditorFor(m => m.Person)

Side note:

  1. Your claim that "This works great when the form starts out blank" means you not passing a new instance of PersonViewModel to your view in the 'Create' method which is poor practice. Your controller method should pass an instance to the view.
  2. Your current template where you manually construct an input element would not work because you never set the value attribute. In addition you do not add the data-val-* attributes used for client side validation. Always use the strongly typed html helpers to generate your html so you get correct 2-way model binding and take advantage of all the built-in features of MVC.

Upvotes: 1

Related Questions