0

I am new to MVC so here is my issue. I have a parent view and a partial view which is rendered inside it. As a model I pass an IEnumerable to the parent view. I iterate thru the list and for each item i render the partial view having the list item as model. On the partial view I have a form which on a submit triggers a child action which accepts as parameter the type of the list. My issue is that the param comes always with it's values null.

These are my domain entities.

public class Contact
    {
        [Key]
        public int IdContacts { get; set; }
        public int UserId { get; set; }
        public int CreatedByUserId { get; set; }
        public int UpdatedByUserId { get; set; }
        public int AddressId { get; set; }
        public string FirstName { get; set; }
        public string MiddleName { get; set; }
        public string LastName { get; set; }
        public long HomePhone { get; set; }
        public long? WorkPhone { get; set; }
        public bool IsRelated { get; set; }
        public bool IsEmergency { get; set; }
        public bool IsDeceased { get; set; }
        public string Relationship { get; set; }
        public DateTime EntryDate { get; set; }
        public DateTime? ChangeDate { get; set; }
    }

 public class Address
    {
        [Key]
        public int IdAddresses { get; set; }
        public int CountryId { get; set; }
        public int StateId { get; set; }
        public int CreatedByUserId { get; set; }
        public int UpdatedByUserId { get; set; }
        public string Street { get; set; }
        public string City { get; set; }
        public long PostalCode { get; set; }
        public string OfficeOrApt { get; set; }
        public int AreaGroup { get; set; }
        public int? SuperUserId { get; set; }
        public DateTime EntryDate { get; set; }
        public DateTime? ChangeDate { get; set; }
    }

This is my view model

public class ContactModel
    {
        public Contact Contact { get; set; }
        public Address Address { get; set; }
        public bool IsEditMode { get; set; }
    }

This is my parent view

@model IEnumerable<Cricket.WebUI.Models.ContactModel>
@{
    ViewBag.Title = "Contacts";
}
<h2 align="center">
    Contacts</h2>
<div class="iggr_container">
    <div class="iggr_clear">
    </div>
    @foreach (var contact in Model)
    {
        ViewDataDictionary dictionary = new ViewDataDictionary();
        string guid = (Guid.NewGuid()).ToString();
        dictionary.Add("prefix", guid);

        @Html.Hidden("Contact.Index", guid)
        @Html.Hidden("Address.Index", guid)
        @Html.Partial("ContactSummary", contact, dictionary)
        <hr style="width: 385px;" align="left" /> 
    }
</div>

This is my partial view

@model Models.ContactModel
<div class="iggr_clear">
</div>
@if (!Model.IsEditMode)
{
    var prefixContact = "Contact[" + ViewData["prefix"] + "].";
    var prefixAddress = "Address[" + ViewData["prefix"] + "].";

    using (Html.BeginForm("Edit", "Contacts", FormMethod.Post, new { enctype = "multipart/form-data" }))
    {
        TempData["ContactModelObject"] = Model;
    <div>
        <b>
            @Html.Hidden(prefixContact + "FirstName", Model.Contact.FirstName);
            @Html.Hidden(prefixContact + "LastName", new { name = "Contact" + ViewData["prefixContact"] + ".LastName" })
            @Html.LabelFor(m => m.Contact.FirstName, Model.Contact.FirstName)
            &nbsp;
            @Html.LabelFor(m => m.Contact.LastName, Model.Contact.LastName)
        </b>
        <div>
            <span>Home Phone:</span>
            @Html.Hidden(prefixContact + "HomePhone", Model.Contact.HomePhone)
            @Html.LabelFor(m => m.Contact.HomePhone, Model.Contact.HomePhone.ToString())</div>
        <div>
            <span>Work Phone:</span>
            @Html.Hidden(prefixContact + "WorkPhone", Model.Contact.WorkPhone)
            <span>
                @if (Model.Contact.WorkPhone == null)
                {
                    @:N/A
            }
                else
                {
                    @Html.LabelFor(m => m.Contact.WorkPhone, Model.Contact.WorkPhone.ToString())
                }
            </span>
        </div>
        <div>
            @Html.Hidden(prefixAddress + "Street", Model.Address.Street)
            @Html.LabelFor(m => m.Address.Street, Model.Address.Street)
        </div>
        <div>
            @Html.Hidden(prefixAddress + "City", Model.Address.City)
            @Html.Hidden(prefixAddress + "PostalCode", Model.Address.PostalCode)
            @Html.LabelFor(m => m.Address.City, Model.Address.City)&nbsp;&nbsp;@Html.LabelFor(m => m.Address.PostalCode, Model.Address.PostalCode.ToString())
        </div>
        @Html.Hidden(prefixContact + "IsRelated", Model.Contact.IsRelated)
        @if (Model.Contact.IsRelated)
        {
            <b>Family</b>
            if (Model.Contact.IsEmergency || Model.Contact.IsDeceased)
            {
            <b>/</b>
            }
        }
        @Html.Hidden(prefixContact + "IsEmergency", Model.Contact.IsEmergency)
        @if (Model.Contact.IsEmergency && !Model.Contact.IsDeceased)
        { 
            <b>Emergency</b>
        }
        @Html.Hidden(prefixContact + "IsDeceased", Model.Contact.IsDeceased)
        @if (Model.Contact.IsDeceased)
        { 
            <b>Deceased</b>
        }
        <input type="submit" name="button" value="Edit" class="iggr_button_edit" style="margin-left: 150px;" />
    </div>
    }
}

And finally my controller class

public class ContactsController : Controller
{
    [HttpGet]
    public ActionResult Index()
    {
        ContactsRepository repository = new ContactsRepository();

        CDE.User user = (from u in repository.Users where u.IdUsers == 1 select u).FirstOrDefault();

        var contacts = (from u in repository.Users
                       join c in repository.Contacts on new { UserId = u.IdUsers } equals new { UserId = c.UserId }
                       join a in repository.Addresses on new { AddressId = c.AddressId } equals new { AddressId = a.IdAddresses }
                       select new ContactModel()
                       {
                           Contact = c,
                           Address = a
                       }).AsEnumerable();

        return View("Contacts", contacts);
    }

    [HttpPost]
    [ActionName("Edit")]
    [@ActionFilter(ActionInvokerType = "button", ActionInvokerValue = "Edit")]
    public ViewResult Edit(ContactModel contact)
    {
        //Here contact.Contact comes as null same for contact.Address
        return View("Contacts", null);//Ignore this line
    }
}
Matthew Abbott
  • 60,571
  • 9
  • 104
  • 129
Michael H.
  • 227
  • 1
  • 4
  • 11

1 Answers1

0

I have a feeling that your prefix structure is interfering with the binding that normally happens in MVC. You could use a custom model binding implementation, or find a way to do without your prefixes.

Timothy Strimple
  • 22,920
  • 6
  • 69
  • 76
  • What I did, I have removed the prefixes for good, but..same issue. using the default model binding for the action parameter. It comes with null values. But, if I do the binding manually, it works.
    UpdateModel(contactModel, formData); Any idea why???
    – Michael H. Sep 08 '11 at 19:08
  • It may have to do with trying to bind to a complex type. I typically flatten my ViewModel to simplify binding. – Timothy Strimple Sep 08 '11 at 19:12
  • Can you just pass the model through to the partial view? – Jared Peless Sep 08 '11 at 19:23
  • Based on what I've read, the model is being passed to the partial view. The problem is when submitting the form on the partial view, databinding is not reconstructing his object. – Timothy Strimple Sep 08 '11 at 19:34
  • Well, I can't flatten the model because is making use of the domain entities, this would mean that my model should have all properties contained by the used entities. – Michael H. Sep 08 '11 at 19:41
  • 1
    In most cases your view should not be working directly with your domain model. One of the best practices recommendations for MVC is to create ViewModels which contain only the information necessary to render your view. Read more here. http://stackoverflow.com/questions/4865806/why-two-classes-view-model-and-domain-model – Timothy Strimple Sep 08 '11 at 19:50
  • I found the issue. The name of the action method parameter was causing a conflict in the binding process. If I change the name from "contact" to "dummyThing" then the automatic binding process will work like a charm. – Michael H. Sep 08 '11 at 20:12