View Model posting null properties back to controller

13,764

Solution 1

Well if adding the hiddenfor did not work I would try to make it something like this.

@for (int i = 0; i < Model.OrdItems.Count; i++)
{

@Html.DisplayFor(model => model.zipCodeTerritory[i].channelCode)@Html.HiddenFor(model => model.zipCodeTerritory[i].channelCode)
@Html.DisplayFor(model => model.zipCodeTerritory[i].zipCode)@Html.HiddenFor(model => model.zipCodeTerritory[i].zipCode)

}

Solution 2

When we use Html Helper method Html.DisplayFor(), it just shows the data as a plain text. You can check it by View Page resource in your browser. What you have do is to use Html.HiddenFor helper method to bind what data you need after post. Or you can also bind data using JQuery.Ajax

Share:
13,764
NealR
Author by

NealR

Updated on September 05, 2022

Comments

  • NealR
    NealR over 1 year

    On my Index page I have a search form that allows users to pull information based on 3 search criteria. When the the search results return from the controller, they are returned as a List object that is a property of the view model and displayed in a table below the search form.

    The user then has the option of selecting which records they would like to alter. They will do this by selecting a check box next to the specified records. Then, using a form that appears below the search box, will enter the new values and hit an "Update" button to save the changes. (we do this in order to allow the user to make mass updates without having to alter the table row by row)

    Here is a screen shot to illustrate what I mean. This is what the page will look like after the user has hit the "Search" button:

    enter image description here

    When the user hit's "Search" the form is instructed to post back to the Index method of the controller. When the user hits "Clone Selected Items" the form is instructed to post back to an "Update" method in the same controller. However, the problem is the view model object that gets posted back to the "Update" method is completely null except for the values placed in the New Territory, New Description, and New Effective Date text boxes.

    I'm relatively new to ASP MVC so any help/suggestions would be appreciated. Not sure why the View Model will post back from the controller with the same values it was sent there while using the "Search" button but will not do so using the "Clone Selected Items" one.

    View Model (this is what gets posted back to the controller)

    public class ZipCodeIndex
    {
        public List<ZipCodeTerritory> zipCodeTerritory { get; set; }
        [DisplayName("Zip Code")]
        public string searchZip { get; set; }
        [DisplayName("Effective on this date")]
        public string searchDate { get; set; }
        [DisplayName("State")]
        public string searchState { get; set; }
        [DisplayName("New Territory")]
        public string newTerritory { get; set; }
        [DisplayName("New Description")]
        public string newDescription { get; set; }
        [DisplayName("New Effective Date")]
        public string newEffectiveDate { get; set; }
    
        public ZipCodeIndex() 
        {
            zipCodeTerritory = new List<ZipCodeTerritory>();
        }
    }
    

    Model (This populates the List object in the View Model)

    [MetadataType(typeof(ZipCodeTerritoryMetaData))]
    public partial class ZipCodeTerritory
    {
        public bool Update { get; set; }
    }
    
    public partial class ZipCodeTerritory
    {
        public string ChannelCode { get; set; }
        public string DrmTerrDesc { get; set; }
        public string IndDistrnId { get; set; }
        public string StateCode { get; set; }
        public string ZipCode { get; set; }
        public System.DateTime EndDate { get; set; }
        public System.DateTime EffectiveDate { get; set; }
        public string LastUpdateId { get; set; }
        public Nullable<System.DateTime> LastUpdateDate { get; set; }
        public int Id { get; set; }
    }
    

    View

    @model Monet.ViewModel.ZipCodeIndex
    
        @using(Html.BeginForm("Index", "ZipCodeTerritory", FormMethod.Post))
        {
            <div id="searchBox" class="boxMe">
                <div id="zipBox">
                    @Html.Raw("Zip Code")
                    @Html.TextAreaFor(model => model.searchZip, new { style = "width: 300px;", placeholder = "Enter up to 35 comma separated zip codes" })
                </div>
                <div id="dateBox">
                    @Html.LabelFor(model => model.searchDate)
                    @Html.TextBoxFor(model => model.searchDate, new { style="width: 80px;"})
                </div>
                <div id="stateBox">
                    @Html.LabelFor(model => model.searchState)
                    @Html.TextBoxFor(model => model.searchState, new { style = "width: 25px;" })
                    <button type="submit">Search</button>
                </div>
            </div>
            <div id="errorStatus">
                @ViewBag.ErrorMessage            
            </div>
            <div style="clear: both;"></div>
        }
    
    <br/>
    @Html.ActionLink("Create New", "Create")
    <br/>
    
    @if (Model != null)
    {
        using(Html.BeginForm("Update", "ZipCodeTerritory", FormMethod.Post))
        {
            <div id="cloneBox">
                @Html.LabelFor(model => model.newTerritory)
                @Html.TextBoxFor(model => model.newTerritory, new { style="width: 30px;padding-left:10px;"})
                @Html.LabelFor(model => model.newDescription)
                @Html.TextBoxFor(model => model.newDescription, new { style = "width: 250px;padding-left:10px;" })  
                @Html.LabelFor(model => model.newEffectiveDate)     
                @Html.TextBoxFor(model => model.newEffectiveDate, new { style = "width: 80px;padding-left:10px;" })   
                <button type="submit">Clone Selected Items</button>                      
            </div>
        }    
    
        <table id="thetable" class="tablesorter" >
            <thead>
                <th></th>
                <th>Channel</th>
                <th>Territory</th>
                <th>Description</th>
                <th>State</th>
                <th>Zip</th>
                <th>Effective</th>
                <th>End Date</th>
                <th>Last Update By</th>
                <th>Last Update Date</th>
                <th></th>
            </thead>
            <tbody>
                @foreach (var item in Model.zipCodeTerritory)
                {
                    <tr>
                        <td>@Html.CheckBoxFor(model => item.Update)</td>
                        <td>
                            @Html.DisplayFor(model => item.ChannelCode)
                        </td>
                        <td>
                            @Html.DisplayFor(model => item.IndDistrnId)
                        </td>
                        <td>
                            @Html.DisplayFor(model => item.DrmTerrDesc)
                        </td>
                        <td>
                            @Html.DisplayFor(model => item.StateCode)
                        </td>
                        <td>
                            @Html.DisplayFor(model => item.ZipCode)
                        </td>
                        <td>
                            @Html.DisplayFor(model => item.EffectiveDate)
                        </td>
                        <td>
                            @Html.DisplayFor(model => item.EndDate)
                        </td>
                        <td>
                            @Html.DisplayFor(model => item.LastUpdateId)
                        </td>
                        <td>
                            @Html.DisplayFor(model => item.LastUpdateDate)
                        </td>
                        <td>
                            @Html.ActionLink("Edit", "Edit", new { id = item.Id })
                        </td>
                    </tr>
                }
            </tbody>
        </table>    
    }
    

    Controller

        public ViewResult Index(ZipCodeIndex search)
        {
            try
            {
                //If search criteria is null page is loading for the first time so send blank view
                if (String.IsNullOrWhiteSpace(search.searchZip) &&
                    String.IsNullOrWhiteSpace(search.searchDate) &&
                    String.IsNullOrWhiteSpace(search.searchState))
                {
                    return View();
                }
    
                //Determine if necessary search criteria has been sent
                if (String.IsNullOrWhiteSpace(search.searchZip) && String.IsNullOrWhiteSpace(search.searchState))
                {
                    ViewBag.ErrorMessage = "Either State or Zip Code Must be Specified";
                    return View(search);
                }
    
                DateTime effectiveDate;
    
                //Convert date string to DateTime type
                if (String.IsNullOrWhiteSpace(search.searchDate))
                {
                    effectiveDate = DateTime.MinValue;
                }
                else
                {
                    effectiveDate = Convert.ToDateTime(search.searchDate);
                }
    
                //Conduct search by State Code/Date alone
                if (String.IsNullOrWhiteSpace(search.searchZip))
                {
                    search.zipCodeTerritory = (from z in db.ZipCodeTerritory
                                               where z.StateCode.Equals(search.searchState) &&
                                                     z.EffectiveDate >= effectiveDate
                                               select z).ToList();
                    return View(search);
                }
    
                //Zip codes have been requested to conduct zip search
                string[] zipArray;
    
                //Create array and remove white spaces
                zipArray = search.searchZip.Split(',').Distinct().ToArray();
                for (int i = 0; i < zipArray.Length; i++)
                {
                    zipArray[i] = zipArray[i].Trim();
                }
    
                //Determine if state code is being used in search
                if (String.IsNullOrWhiteSpace(search.searchState))
                {
                    foreach (var zip in zipArray)
                    {
                        var item = from z in db.ZipCodeTerritory
                                   where z.ZipCode.Equals(zip) &&
                                          z.EffectiveDate >= effectiveDate
                                   select z;
                        search.zipCodeTerritory.AddRange(item);
                    }
                }
                else
                {
                    foreach (var zip in zipArray)
                    {
                        var item = from z in db.ZipCodeTerritory
                                   where z.ZipCode.Equals(zip) &&
                                          z.EffectiveDate >= effectiveDate &&
                                          z.StateCode.Equals(search.searchState)
                                   select z;
                        search.zipCodeTerritory.AddRange(item);
                    }
                }
            }
            catch (DbEntityValidationException dbEx)
            {
                ViewBag.ErrorMessage = "An error has occurred, we apologize for the incovenience. IT has been notified and will resolve the issue shortly.";
                SendEmail.ErrorMail(Common.ErrorCheck.CombineDbErrors(dbEx));
            }
            catch (Exception ex)
            {
                ViewBag.ErrorMessage = ErrorCheck.FriendlyError(ex);
                SendEmail.ErrorMail(ex);
            }
    
            return View(search);
        }
    
    
        [HttpPost]
        public ActionResult Update(ZipCodeIndex updateZip)
        {
            foreach (var zipCode in updateZip.zipCodeTerritory)
            {
                if (zipCode.Update)
                {
                    try
                    {
                        if (!string.IsNullOrEmpty(updateZip.newTerritory)) zipCode.IndDistrnId = updateZip.newTerritory;
                        if (!string.IsNullOrWhiteSpace(updateZip.newDescription)) zipCode.DrmTerrDesc = updateZip.newDescription;
                        if (!string.IsNullOrWhiteSpace(updateZip.newEffectiveDate)) zipCode.EffectiveDate = Convert.ToDateTime(updateZip.newEffectiveDate);
    
                        db.Entry(zipCode).State = EntityState.Modified;
                        db.SaveChanges();
                    }
                    catch (DbEntityValidationException dbEx)
                    {
                        ViewBag.ErrorMessage = "An error has occurred, we apologize for the incovenience. IT has been notified and will resolve the issue shortly.";
                        SendEmail.ErrorMail(Common.ErrorCheck.CombineDbErrors(dbEx));
                    }
                    catch (Exception ex)
                    {
                        ViewBag.ErrorMessage = "An error has occurred, we apologize for the incovenience. IT has been notified and will resolve the issue shortly.";
                        SendEmail.ErrorMail("Zip Code not updated: " + zipCode.ToString() + " |MESSAGE| " + ex.Message);
                    }
                }
            }
    
            return RedirectToAction("Index", updateZip);
        }
    

    EDIT

    I've added the following hidden fields to the second form (that posts to the Update method). This will send back the search criteria however the List object is still empty.

    @if (Model != null)
    {
        using(Html.BeginForm("Update", "ZipCodeTerritory", FormMethod.Post))
        {
            @Html.HiddenFor(model => model.searchZip)
            @Html.HiddenFor(model => model.searchDate)
            @Html.HiddenFor(model => model.searchState)
            @Html.HiddenFor(model => model.zipCodeTerritory)
    
            <div id="cloneBox">