Submitting Form in MVC 4 model is null in controller post method

41,742

You are doing a foreach on the views, so the input elements should have the values posted somewhere like to this : name="BillingCodes[0].EnterTimeHours", name="BillingCodes[0].EnterTimeMinutes" you can inspect in the network tab the request on Chrome Developer Tools (CTRL+SHIFT+C) or just viewing the source. If this is the case, you are submitting multiple BillingCodeObj objects. You must have a controller that receive that.

Take a look at the source code as this can greatly help you understand what's going on behind the scenes.

Try this on your controller:

[HttpPost]
public void SubmitTimesheet(IEnumerable<BillingCodeObj> billingCodes){
}

You can also (for debugging purposes) do

public void SubmitTimesheet(FormCollection form){}

and inspect the form how is populated on debug.

after comments and more code provided change your view to :

@using (Html.BeginForm("SubmitTimesheet", "Timesheet", FormMethod.Post))
{
    @Html.EditorFor(m=>m.BillingCodes)
}

create a new cshtml in EditorTemplates/BillingCodeObj.cshtml :

@model BillingCodeObj
<div class="button-padding">
    <a class="btn btn-large btn-danger btn-block billCodeBtn">
        <div class="btnText">@Model.Name</div>
        <div class="btnTime">@Model.TotalHours</div>

        <i class="icon-chevron-down billCodeIconUp billCodeIcon"></i>
        <i class="hidden icon-chevron-up billCodeIconDown billCodeIcon"></i>
    </a>

    <div class="content" >
        <div class="row timeEntry">
            <p></p>
            <div class="col-12 col-lg-2">
                Enter Time: 
    <div class="row">
        <div class="col-12">
            @Html.DropDownListFor(model => model.EnterTimeHours, new SelectList(new[] {
                new { Value = "0", Text = "0" },
                new { Value = "1", Text = "1" },
                new { Value = "2", Text = "2" },
                new { Value = "3", Text = "3" },
                new { Value = "4", Text = "4" },
                new { Value = "5", Text = "5" },
                new { Value = "6", Text = "6" },
                new { Value = "7", Text = "7" },
                new { Value = "8", Text = "8" },
                new { Value = "9", Text = "9" },
                new { Value = "10", Text = "10" },
                new { Value = "11", Text = "11" },
                new { Value = "12", Text = "12" },
            }, "Value", "Text")) <b>:</b> 
            @Html.DropDownListFor(model => model.EnterTimeMinutes, new SelectList(new[] {
                new { Value = "0", Text = "00" },
                new { Value = "15", Text = "15" },
                new { Value = "30", Text = "30" },
                new { Value = "45", Text = "45" },
            }, "Value", "Text"))

        </div>
    </div>
            </div>
            <div class="col-lg-2"></div>

            <div class="col-lg-1"></div>
            <div class="control-group col-12 col-lg-2">
                <label class="checkbox">
                    Billable @Html.CheckBoxFor(model => model.Billable)
                </label>
            </div>
            <div class="col-12 col-lg-2">
                Enter Memo:
    <div class="row">
        <div class="col-12">
            @Html.TextAreaFor(model => model.Comment)
        </div>
    </div>
Share:
41,742
Brandon Knight
Author by

Brandon Knight

Updated on August 01, 2022

Comments

  • Brandon Knight
    Brandon Knight almost 2 years

    So my problem right now is that I cant get my model into my controller when I submit this following form. I am trying to have the items from the BillingCodes (which is a list of BillingCodeObjects) loop through and display. I have removed some code from these that isn't really relevant to the situation to make it shorter and easier to read.

    Here is the code for my view...

    @using (Html.BeginForm("SubmitTimesheet", "Timesheet", FormMethod.Post))
    {
    
    
    foreach (var item in Model.BillingCodes)
    {
    
        <div class="button-padding">
            <a class="btn btn-large btn-danger btn-block billCodeBtn">
                <div class="btnText">@item.Name</div>
                <div class="btnTime">@item.TotalHours</div>
    
                <i class="icon-chevron-down billCodeIconUp billCodeIcon"></i>
                <i class="hidden icon-chevron-up billCodeIconDown billCodeIcon"></i>
            </a>
    
            <div class="content" >
                <div class="row timeEntry">
                    <p></p>
                    <div class="col-12 col-lg-2">
                        Enter Time: 
            <div class="row">
                <div class="col-12">
                    @Html.DropDownListFor(model => item.EnterTimeHours, new SelectList(new[] {
                        new { Value = "0", Text = "0" },
                        new { Value = "1", Text = "1" },
                        new { Value = "2", Text = "2" },
                        new { Value = "3", Text = "3" },
                        new { Value = "4", Text = "4" },
                        new { Value = "5", Text = "5" },
                        new { Value = "6", Text = "6" },
                        new { Value = "7", Text = "7" },
                        new { Value = "8", Text = "8" },
                        new { Value = "9", Text = "9" },
                        new { Value = "10", Text = "10" },
                        new { Value = "11", Text = "11" },
                        new { Value = "12", Text = "12" },
                    }, "Value", "Text")) <b>:</b> 
                    @Html.DropDownListFor(model => item.EnterTimeMinutes, new SelectList(new[] {
                        new { Value = "0", Text = "00" },
                        new { Value = "15", Text = "15" },
                        new { Value = "30", Text = "30" },
                        new { Value = "45", Text = "45" },
                    }, "Value", "Text"))
    
                </div>
            </div>
                    </div>
                    <div class="col-lg-2"></div>
    
                    <div class="col-lg-1"></div>
                    <div class="control-group col-12 col-lg-2">
                        <label class="checkbox">
                            Billable @Html.CheckBoxFor(model => item.Billable)
                        </label>
                    </div>
                    <div class="col-12 col-lg-2">
                        Enter Memo:
            <div class="row">
                <div class="col-12">
                    @Html.TextAreaFor(model => item.Comment)
                </div>
            </div>
    

    And here is some code for my controller:

    public class TimesheetController : Controller
    {
        //
        // GET: /Timesheet/
    
        public ActionResult Index()
        {
    
            string getBillingCodeUrl ="";
    
          //SOME CODE REMOVED FOR LENGTH / READABILITY 
    
            foreach (var entryItem in timePeriod.TimeEntries[0].EntryCollection)
            {
                foreach (var billingItem in billingCodeList.BillingCodes)
                {
                    if (entryItem.BillingCode == billingItem.Name)
                    {
                        //update record in billingItem with data from entryItem
                        billingItem.Comment = entryItem.Comment;
                        billingItem.Billable = entryItem.Billable;
                        billingItem.TotalHours = entryItem.Hours;
                    }
                }
            }
    
            return View(billingCodeList);
        }
        [HttpPost]
        public void SubmitTimesheet(BillingCodeList model)
        {
    
            string uri = "";
    
            foreach (var billingCode in model.BillingCodes)
            {
               //do stuff with each of these
            }
        }
    
    }
    }
    

    and lastly, here is the info that is in the model:

        public class BillingCodeList
        {
            public List<BillingCodeObj> BillingCodes;
        }
    
        public class BillingCodeObj
        {
            public string Name { get; set; }
            public decimal TotalHours { get; set; }
    
            public decimal EnterTimeHours { get; set; }
            public decimal EnterTimeMinutes { get; set; }
            public bool Billable { get; set; }
            public string Comment { get; set; }
    
            public BillingCodeObj(string name, decimal hours)
            {
                this.Name = name;
                this.TotalHours = hours;
            }
            public BillingCodeObj()
            {
    
            }
        }
    

    here is a picture of the debug locals when the form is returned..

    image of locals

  • Brandon Knight
    Brandon Knight almost 11 years
    Hmm. I think you are right, but the List of billingCodes in the model object I get back is still null.. any ideas? I will edit my question to include your code.
  • Brandon Knight
    Brandon Knight almost 11 years
    Okay, thanks. The first thing did not work, billingCodes object is still null. So I will take some time and inspect the form it returns.
  • Brandon Knight
    Brandon Knight almost 11 years
    I am doing: BillingCodeList billingCodeList = JsonConvert.DeserializeObject<BillingCodeList>(result);
  • Bart Calixto
    Bart Calixto almost 11 years
    if you can post the generated inputs on the html I will happily try to help you.
  • Brandon Knight
    Brandon Knight almost 11 years
    okay I edited my original post and included a picture of the locals also here: link
  • Bart Calixto
    Bart Calixto almost 11 years
    from what I see, mvc is interpreting you are not sending a collection but one. public void SubmitTimesheet(BillingCodeObj item){ <-- this works ?
  • Brandon Knight
    Brandon Knight almost 11 years
    Yeah you're right that does work. So if I enter the information for more than one billing code at once though it only submits one of them..
  • Bart Calixto
    Bart Calixto almost 11 years
    One solution will be to change your view so instead of doing a foreach do an EditorFor(m=> m. BillingCodes) and have a EditorTemplate for the BillingCodeObj in EditorTemplates/BillingCodeObj.cshtml or using a partial. Another solution might be using BeginCollectionItem helper blog.stevensanderson.com/2010/01/28/…
  • Brandon Knight
    Brandon Knight almost 11 years
    it just lists the codes like so when i try and make a template and put the code to generate them in there instead of putting buttons? I have never used the editortemplate before so i might be doing something wrong... TrainingPre-Sales SupportTime Off: BereavementTime Off: Floating HolidayTime Off: HolidayTime Off: PTO (Paid Time Off)Create documentation for how to make homescreen icons on all platformsResearch AzureResearch AzureResearch MS Project/TFS Project server integration and link the twoResearch MS Proyecto/TFS integration and link the twoTest TaskWrite up Initial User Stories }
  • Bart Calixto
    Bart Calixto almost 11 years
    For creating EditorTemplates: 1) Check folder is EditorTemplates and not EditorTemplate 2) FileName should be = class name and html must have a @model directive with this class. In this case I think is BillingCodeObj 3) If any of that doesn't work, take a look at : stackoverflow.com/questions/14655930/…
  • Bart Calixto
    Bart Calixto almost 11 years
    perfect! now controller should receive (IEnumerable<BillingCodesObj> billingCodes)