0

I would like to dinamically add and remove items from a POCO Object and store it on a related table. for instance:

class Contact{
    [Key]
    public int id {get; set;}
    [Required] public string name {get; set;}
    public IEnumerable<Phone> phones{get; set;}
}

class Phone{
    [Key]
    public int id {get;set;}
    [Required] public string phone_type {get; set;}
    [Required] public string phone_number {get; set;}
}

where Contact is able to have a lot of phones.

The Contact Edit View is like this:

@model SGD.Models.Contact
@Html.LabelFor(model => model.name)
@Html.EditorFor(model => model.name)

@Html.LabelFor(model => model.phones)
<div id="phones"></div>

<a href="#" onclick="addPhone()">Add new phone</a>

<script>
    function addPhone() {
        $.ajax({url: "/Phones/_Phone",
             cache: false,
             success: function(html) { $("#phones").append(html);}}
    )}
</script>

the "Add new phone" link button append this partial view inside #phones div

@model SGD.Models.Phone
@{
    Layout = null;
}

    @Html.HiddenFor(model => model.id)

    @Html.LabelFor(model => model.phone_type)
    @Html.EditorFor(model => model.phone_type)
    @Html.ValidationMessageFor(model => model.phone_type)

    @Html.LabelFor(model => model.phone_number)
    @Html.EditorFor(model => model.phone_number)
    @Html.ValidationMessageFor(model => model.phone_number)

But I Don't know how to handle and bind the post data in the controller and store the contact and the related phone records on DB. How can I do it?

Daniel Santos
  • 14,328
  • 21
  • 91
  • 174

1 Answers1

2

First, I would check out this article by Phil Haack.

You will need some mechanism in your javascript to apply indexing to your phone partial, but in a nutshell your partial needs to look more like this:

@model SGD.Models.Phone
@{
    Layout = null;
}

<input name="phones[0].id" style="display:none;"/>

@Html.LabelFor(model => model.phone_type)
<input name="phones[0].phone_type" />

@Html.LabelFor(model => model.phone_number)
<input name="phones[0].phone_number" />

As for the database part, I am assuming you are using Entity Framework code-first based on the models you've shown. There are some problems with your code-first models in that case. Read this msdn article to learn how to properly construct code-first models for different types of relationships. I'm guessing you intend to have a one-to-many relationship between contacts and phones, where one contact may have many phones. In that case, your models should be as follows:

class Contact{
    [Key]
    public int Id {get; set;}
    public string name {get; set;}
    public ICollection<Phone> phones{get; set;}
}

class Phone{
    [Key]
    public int id {get;set;}
    public string phone_type {get; set;}
    public string phone_number {get; set;}
    public Contact contact { get; set; }
}

From there, use your context to add new phones to the appropriate contacts like so in your AddPhone action method:

public ActionResult AddPhone(int ContactId)
{
    var newPhone = new Phone();
    Contact ct = ctx.Contacts.Find(ContactId);
    ct.Phones.Add(newPhone);
    ctx.SaveChanges();
    return View(newPhone);
}

You will also need to implement EditPhone and DeletePhone actions.

As for the [Required] attributes, you either need to remove them or re-think your view entirely. You can't just "addphone" with required attributes without taking any input first. You need to get the input from the user before you can bind it, and I currently don't see any effort on your part toward that end.

Jakotheshadows
  • 1,485
  • 2
  • 13
  • 24