0

I am a beginner in ASP MVC, and, after a lot of help from SO, am progressing through ViewModels. Using a ViewModel however, I have encountered the following error.

Given the following View:

@model November.ViewModels.Staff_Salutation_VM

//...

using (Html.BeginForm("UpdateStaff", "Settings", FormMethod.Post, 
    new { @class = "clearfix parameter-form update-parameter update-staff", enctype = "multipart/form-data" }))
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    //...       

    @for (int i = 0; i < Model.AvailableStaffMembers.Count; i++)
    {
        var staff = Model.AvailableStaffMembers[i];
        <tr>               
            <td>@Html.HiddenFor(model => staff.ID)@Html.ValueFor(model => staff.ID)</td>
            <td>
                @Html.DropDownListFor(  
                    model => model.SalutationID, Model.AvailableSalutations.Select(option => new SelectListItem 
                        {
                            Text = option.Desc.ToString(),
                            Value = option.ID.ToString(),
                            Selected = (option.ID.ToString() == staff.SalutationID.ToString())
                        }
                    ), 
                "Choose...")
            </td>
            <td>@Html.EditorFor(model => staff.FName)</td>
            <td>@Html.EditorFor(model => staff.LName)</td>
            <td>@Html.EditorFor(model => staff.Active)</td>
            <td><a href="/Settings/[email protected](model => staff.ID)">Delete</a></td>
        </tr>
    }

and the following Controller:

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Web;
 using System.Web.Mvc;
 using November.Models;
 using November.ViewModels;
 using November.DAL;   

 //...

 //GET
 var staffCreateViewModel = new Staff_Salutation_VM();

 staffCreateViewModel.AvailableSalutations = new List<Prm_Salutation>();
 var activeSalts = (from a in db.Prm_Salutations
                     where a.Active == true
                     orderby a.Desc ascending
                     select a);
 staffCreateViewModel.AvailableSalutations = activeSalts.ToList();

 staffCreateViewModel.AvailableStaffMembers = new List<Prm_Staff>();
 var activeStaff = (from a in db.Prm_Staffs
                     where a.Active == true
                     orderby a.LName ascending
                     select a);
 staffCreateViewModel.AvailableStaffMembers = activeStaff.ToList();

 return View("StaffMembers", staffCreateViewModel);



 //POST
 public ActionResult UpdateStaff(Staff_Salutation_VM list)
 {
      if (ModelState.IsValid)
      {
           foreach (var formData in list) //no longer works due to dropping List<>
           {
                var tbl = db.Prm_Staffs.Where(a => a.ID.Equals(formData.ID)).FirstOrDefault();
                if (tbl != null)
                {
                     var Prm_StaffModel = new Prm_Staff();

                     Prm_StaffModel.SalutationID = formData.SalutationID;
                     Prm_StaffModel.FName = formData.FName;
                     Prm_StaffModel.LName = formData.LName;
                     Prm_StaffModel.Active = formData.Active;
                }
           }
           db.SaveChanges();
           ViewBag.UpdateRtrn = "Successfully Updated.";
           return RedirectToAction("Parameters", new { param = "Staff Members" });
      }
      else
           {
                ViewBag.UpdateRtrn = "Failed ! Please try again.";
                return RedirectToAction("Parameters", new { param = "Staff Members" });
           }
      }
      return RedirectToAction("Parameters", new { param = "Staff Members" });
 }

And, for good measure, the ViewModel itself:

 public class Staff_Salutation_VM
 {
      public int ID { get; set; }
      public int SalutationID { get; set; }
      public string FName { get; set; }
      public string LName { get; set; }
      public bool Active { get; set; }

      public List<Prm_Salutation> AvailableSalutations { get; set; }
      public List<Prm_Staff> AvailableStaffMembers { get; set; }

      public Staff_Salutation_VM() { }        
 }

When triggered, no form values populate the ActionResult, resulting in a Object reference not set to an instance of an object. exception being thrown when the foreach (var formData in list) line is reached. Debugging shows list as being null. How can this be so? Or rather, what am I doing wrong?

EDIT: the list variable in my POST ActionResult is now getting data - or at least, is showing the various types in the class when debugged. How do I then iterate through it to save that data in the appropriate rows of the DB?

7
  • What happens if you remove enctype = "multipart/form-data" and re-run? Also, can you post your Action that renders the view initially? Commented Dec 5, 2013 at 17:57
  • @StinkyTowel Same result, I'm afraid. Note that there are two other ActionResults for this same view (a create form and a delete action) but they are named diffrently. I don't believe that they are a factor. Commented Dec 5, 2013 at 18:02
  • Im not sure if modelbinding works this way, I think you should get the values from Request.Form and parse them yourself. Commented Dec 5, 2013 at 18:23
  • @Marthijn I'm sorry (beginner), where do I access Request.Form? Commented Dec 5, 2013 at 18:29
  • @Eamonn in an ActionResult Commented Dec 5, 2013 at 18:53

2 Answers 2

1

I totally missed the method signature, sorry! Your initial view load passes a model Staff_Salutation_VM but your UpdateStaff (form posted) is expecting List<Staff_Salutation_VM>. These are different animals. Change public ActionResult UpdateStaff(List<Staff_Salutation_VM> list) to public ActionResult UpdateStaff(Staff_Salutation_VM staff) just to see if you get past the null ref exception. Note, you'll need to remove your foreach since you don't have an IEnumerable coming in.

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

5 Comments

Ok, now list contains {November.ViewModels.Staff_SalutationVM} which expands out to FName, LName, Active, etc. Those keys dont seem to have any values themselves other than null or 0. I will need to iterate through them to find out. How do I put this into a List interface again? Just .ToList()?
Although your incoming parameter is called list, its not a List<>, but a Staff_Salutation_VM type, so you cannot iterate over it. However, are you asking about iterating over AvailableStaffMembers within Staff_Salutation_VM? Could you update your post with the code for the Staff_Salutation_VM Model?
Yeah, now its just a Staff_Salutation_VM type, but will I not need to iterate through it to update the records in the DB? I have multiple rows echoed out in my View that are all being updated - I just assumed I'd have to loop through the returned data in some way to save it. I'll update my question now...
Yes, but updating the db is outside the scope of your initial post. Just to be clear though, your model is populated with the expected values when posted to UpdateStaff()? As far as updating your db, you could return whatever you need to your DAC - your populated model, or a smaller DTO with only the values needed for the db. You DAC layer would handle iterating over the list and insert/update accordingly.
Apparently so - the action now only fails (as expected) upon reaching the foreach. Given that you have solved my initial problem, I'll accept your answer (with thanks!). I will post a new question regarding the updating of the database - I'm afraid your explaination is beyond my current level of understanding. Thanks tho :)
0

I hope this post will be helpful for you. Model Binding To A List

3 Comments

Thanks for the link, I've looked over it though, and (although I very well may have misunderstood the article) I'm not sure that binding is my problem - there's no data coming in at all to map to. I just don't know how this can be...
You can add to your action FormCollection parameter and examine it, if there is any form data. If data will be presented in this collection, than ModelBinding is your problem.
There isn't any form data. That's my problem :)

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.