0

Pretty new to MVC and the like. I have a class the looks like this:

public class SomeExampleModel
{
    public int Id { get; private set; }
    public string Name { get; private set;}
    public string Street { get; private set; }
    public IList<Contact> Contacts { get; private set; }
    ...
}

Where Contact looks like:

public class Contact
{
    public int Id { get; private set; }
    public int SomeExampleModelId { get; private set; }
    public ContactType Type { get; private set; }
    public string ContactValue { get; private set; }
...
}

Now the problem is, I have a Post Create action and Create.cshtml view to add new SomeExampleModel to my database. It works great for all the basic properties, but there isn't anything for the Contacts property (which is a separate table in the database).

How would I be able to add contacts (single for now, plural in the future) using forms on my view?

EDIT: I am sorry if I was not clear. The problem is not getting data to save in the database correctly. I have tested that already and it works fine if I just manually insert a SomeExampleModel record into the database with the SomeExampleContext. What I dont know is how to draft my View so that it allows users to add Contacts to the record

9
  • Do you also have ContactType declaration ? what back-end do you use in the project (EF with MsSQL)? any ORMs? Commented Jun 20, 2012 at 2:07
  • ContactType is an enum that, right now, can only be Email (0), or Phone (1). EF 4.3.1 is used for the back-end (and I use some trickery to get Enums to work). Commented Jun 20, 2012 at 2:10
  • Well if you are using EF4.1 or above, you do not need any trick. Look at official usage - blogs.msdn.com/b/efdesign/archive/2011/06/29/… Commented Jun 20, 2012 at 2:12
  • The problem is probably due to either the Contact objects not being bound correctly when your post is executed, which results in an empty list being passed to your write command, or in the actual DB write failing even with a populated list. When you debug the Post controller method, is the Contacts property populated? Commented Jun 20, 2012 at 2:17
  • 2
    @Killnine, You can find really good reference material here: weblogs.asp.net/nmarun/archive/2010/03/13/…, and here: hanselman.com/blog/… These are far better than I can write up as an answer for you. Commented Jun 20, 2012 at 2:48

2 Answers 2

1

Here is one approach using an EditorTemplate. I have made minor changes to your model classes (this works; however, note that this is only for you to understand the concept. You can extend upon this)

Models

public class SomeExampleModel
{
    public int Id { get; set; }
    public string Name { get; set;}
    public string Street { get; set; }
    public IList<Contact> Contacts { get; set; }    
}

public class Contact
{
    public int Id { get; set; }
    public int SomeExampleModelId { get; set; }
    public ContactType Type { get; set; }
    public string ContactText { get { return Type.ToString(); } }
    public string ContactValue { get; set; }
}

public enum ContactType
{
    email,
    Phone,
    mobile,
    fax
}

Make a note that I've created a property ContactText that returns the enum text (for display purposes)

Create a editor template for Contact (named Contact.cshtml; Template name must match the class name). Find below the screen shot on where to place your editor template.

enter image description here

Here is the code for Contact.cshtml

@model Test1.Models.Contact
<table>
@Html.HiddenFor(a=>a.Type)
<tr>
 <td>@Html.Label(Model.ContactText)</td>
 <td>@Html.TextBoxFor(a => a.ContactValue)</td>
</tr>
</table>

Here is the code for the 'Create' view (ExampleCreateView.cshtml in my case)

@model Test1.Models.SomeExampleModel

@{
    ViewBag.Title = "ExampleCreateView";
}

<h2>ExampleCreateView</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>SomeExampleModel</legend>
        @Html.HiddenFor(model=>model.Id)
        <table>
            <tr>
                <td>@Html.LabelFor(model=>model.Name)</td>
                <td>@Html.EditorFor(model=>model.Name)</td>
            </tr>
            <tr>
                <td>@Html.LabelFor(model=>model.Street)</td>
                <td>@Html.EditorFor(model=>model.Street)</td>
            </tr>
            <tr>
                <td>@Html.LabelFor(model=>model.Contacts)</td>
                <td>@Html.EditorFor(model=>model.Contacts)</td>
            </tr>
        </table>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Make a note on how I've used @Html.EditorFor for the Contacts property.

Here is how the Get, Post actions will look like

    public ActionResult ExampleCreateView()
    {
        SomeExampleModel model = new SomeExampleModel();
        Contact contactEmail = new Contact();
        contactEmail.Type = ContactType.email;

        Contact contactFax = new Contact();
        contactFax.Type = ContactType.fax;

        Contact contactPhone = new Contact();
        contactPhone.Type = ContactType.Phone;

        Contact contactMobile = new Contact();
        contactMobile.Type = ContactType.mobile;

        List<Contact> contacts = new List<Contact>();

        contacts.Add(contactEmail);
        contacts.Add(contactFax);
        contacts.Add(contactPhone);
        contacts.Add(contactMobile);

        model.Contacts = contacts;

        return View(model);
    }

    [HttpPost]
    public ActionResult ExampleCreateView(SomeExampleModel model)
    {
        //Your operations
        return View(model);
    }

Run the application. This is how the view looks like

enter image description here

Screen shot of what you will get in the POST action

enter image description here

Sign up to request clarification or add additional context in comments.

4 Comments

Absolutely excellent example. However, I am having trouble getting the Contact forms to show up in my view. I think it may be because I pulled my SomeExampleModel into a separate 'Domain' project (along with the Contact class). Is that confusing MVC and the conventions it is expecting, you think?
@Killnine what do you mean separate 'Domain'project; you mean a separate namespace? That won't be an issue. If you have already done it for 'name', 'street' with SomeExampleModel it should work fine for Contact as well. All you need to make sure is to provide the fully qualified names for the respective models(namespace.modelclass format). Make sure to follow the steps from my answer (also the directory structure should be correct without any spelling mistakes; Views->Shared->EditorTemplates->Contact.cshtml). Also make sure Contact.cshtml has the correct model specified on top.
yeah, different namespace. Ill give it a closer look. This is exactly what I was looking for, though. Thanks for the very thorough, detailed explanation.
UPDATE: Got it working! Was missing the return View(model) where you pass in the default model on the Get action. Awesome!
0

The way I would do it is to have two separate actions - one that does the initial create of SomeExampleModel, and a separate action for adding a Contact to that model.

That way your create SomeExampleModel view would just have Name and street, and when it saved you would show a readonly version of the SomeExampleModel . The readonly version of SomeExampleModel would list all related contacts in a table below the Name and Street, with an edit and delete link, and an 'add new' contact link under the table

e.g.

<table>
@foreach (var contact in Model.Contacts)
{
    <tr>
        <td>@contact.ContactType</td>
        <td>@contact.ContactValue</td>
        <td>@Html.Action("Edit", "Edit", "Contact",  new { id = contact.Id }</td>
        <td>@Html.Action("Delete", "Delete", "Contact", { id = contact.Id }</td>
    </tr>
}
</table>
@Html.Action("Add new contact", "Add", "Contact" new { id = Model.Id }

Initially, there would be no contacts listed, then later you would have multiple contacts.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.