What's the proper way to add a form to the Index page that posts to the Create action, including valiation?

I have an Index view in my application that shows a list of vendors. I also want to add a small form to add new items right on that page. The create form will post to the Create action. My model class contains a list of vendors, plus one property for a single vendor named NewVendor.

public IEnumerable<SoftwareVendor> Vendors { get; set; }    
public SoftwareVendor NewVendor { get; set; }

The SoftwareVendor class has validation attributes. It's an Entity Framework class.

Making a form that posts to the Create action is easy:

@using (Html.BeginForm( "Create", "Vendor" )) {
    <legend>New Software Vendor</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.NewVendor.Name)
    <div class="editor-field">
        @Html.EditorFor( model => model.NewVendor.Name )
        @Html.ValidationMessageFor( model => model.NewVendor.Name )
    <br />
    <input type="submit" value="Create" />

This posts just fine, and client-side validation also works. However, the default Create action takes an instance of SoftwareVendor and is looking for a key in the form collection called "Name". Instead, the above form posts "NewVendor.Name".

I can remedy this by specifying a template and field name in @Html.EditorFor.

@Html.EditorFor( model => model.NewVendor.Name, "string", "Name" )

Now the Create action is happy because the "Name" value is being received. However, the validation message is broken because it is still looking for a field named "NewVendor.Name", and there seems to be no way to override this.

<span class="field-validation-valid" data-valmsg-for="NewVendor.Name" data-valmsg-replace="true"></span>

Is there something simple I'm missing to make this work?

Here is a list of things I can do to solve this:

  1. Have my Create action take an instance of my Index model instead of a SoftwareVendor. I still have a traditional Create view, though, and I don't want to do this.
  2. Don't have my Create action take any parameters. Instead, manually look at the form keys and pull the name from either "Name" or "NewVendor.Name", whichever is there.
  3. Have the Create action take both model classes and detect which one got populated properly. This is a lot like #2 but I'm checking properties for non-null values instead of checking the form collection.
  4. Figure out how to make a model binder that will perform what #2 is doing. This seems overly complicated, and I'm going to have this problem in a number of pages, so I'm hoping for an easier way.
  5. Use javascript to make the post instead of a form submit, so I can control the exact field names I'm posting. This works, but I'd prefer to leverage an HTML form, since that's what it's for.
  6. Use the overload of EditorFor to specify the field name, and create the validation message manually.
  7. Write my own extension method on HtmlHelper for a new ValidationMessageFor that can override the field name.

Of these options, #2 or #5 are the ones I think I'd choose from unless there's a better way.


Well, this worked:

@Html.EditorFor( model => model.NewVendor.Name, "string", "Name" )
@Html.ValidationMessage( "Name" )

Since my only real problem with my above code was a broken validation message, this seems to solve my problem. I'm still curious if there is a better solution overall.

Need Your Help

Unexpected behavior of C++ boolean function and impossible return

c++ return return-value

I have just encountered an extremely strange result of the following code.

class variables is shared across all instances in python?

python class global-variables instance-variables member

I started coding in python a week ago, it is my mistake i started coding using oops,classes and objects that soon. I assumed my C++ proficiency will help.... I got bit by the following code