1

It's time to ask the internet. I'm a student and really new to MVC + coding in general, but I can't for the life of me figure out why this isn't working. Probably something really obvious. :/

I have a View (AddMemberToGroup) that is strongly-typed to a viewmodel (PersonGroupingViewModel). What am I trying to do is add a Person to a Group, with the user selecting a group from a dropdown list in the View.

Viewmodel:

public class PersonGroupingViewModel
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set;}

    public List<Group> Memberships { get; set; }

    public SelectList AllGroups { get; set; }
    public int SelectedGroupId { get; set; }

}

Controller:

//GET People/AddToGroup
public ActionResult AddMemberToGroup(int? PersonId)
{
    if (PersonId == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 
    }

    Person person = db.People.Find(PersonId);
    if (person == null)
    {
        return HttpNotFound();
    }

    SelectList allthegroups = new SelectList(db.Groups, "GroupId", "Name");

    PersonGroupingViewModel viewmodel = new PersonGroupingViewModel();
    viewmodel.PersonId = person.PersonId;
    viewmodel.FirstName = person.FirstName;
    viewmodel.LastName = person.LastName;
    viewmodel.AllGroups = allthegroups;

    //viewmodel.Memberships cannot be empty
    if (person.Memberships == null)
    {
        viewmodel.Memberships = new List<Group>();
    }
    else 
    { 
        viewmodel.Memberships = person.Memberships.ToList(); 
    }

    return View(viewmodel);
}

//POST: People/AddToGroup 
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddMemberToGroup(PersonGroupingViewModel vm)
{
    SelectList allthegroups = new SelectList(db.Groups, "GroupId", "Name");
    vm.AllGroups = allthegroups; 

    int PersonId = vm.PersonId;
    int GroupId = vm.SelectedGroupId;

    Person person = db.People.Find(PersonId);
    Group group = db.Groups.Find(GroupId);
    group.Members.Add(person);
    db.SaveChanges();

    return View(vm);
}

View form (strongly-typed to PersonGroupingViewModel):

Add Member To Group


@using (Html.BeginForm())
{
@Html.AntiForgeryToken()

<div>
    <h4>Groups @Html.DisplayFor(model => model.FirstName) is already in:</h4>
    <ul>
        @foreach (var group in Model.Memberships)
        {
            <li>@Html.DisplayFor(modelItem => group.Name)</li>
        }
    </ul>
</div>

<div class="form-horizontal">
    <h4>Add @Html.DisplayFor(model => model.FirstName) @Html.DisplayFor(model => model.LastName) To Group:</h4>

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

    <div class="form-group">
        <label>Group: </label>
        @Html.DropDownListFor(m => m.SelectedGroupId, Model.AllGroups, String.Empty)
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Add To Group" class="btn btn-default" />
        </div>
    </div>
</div>
}

When I click 'submit' in the browser I get back a URL: localhost:54696/People/AddMemberToGroup?PersonId=1

Along with exception "Object reference not set to an instance of an object" on the line Group group = db.Groups.Find(GroupId); in the controller.

Is the viewmodel coming back empty or not at all? I am not sure what is going on and would appreciate someone attempting explaining it in small words. I've done a lot of Googling and tried several suggestions from that but in the end I feel as though I'm going in circles.

Richard Seal
  • 4,248
  • 14
  • 29
  • As far as the url goes, change method to `AddMemberToGroup(int? ID)` assuming your using the default routes or add a specific route `url: yourController/AddMemberToGroup/{PersonId}` –  Oct 27 '15 at 21:36
  • Your also generating a `null` label option for the select and not checking `ModelState` so if no group is selected your will likely throw an exception. You need to debug you code and check that all values are correctly set and not `null`. However I suggest that this is a poor user interface. You can select only one group at a time, and you can also select groups that have already been selected (also possibly throwing an exception) and your not reassigning the value of `vm.Memberships` before you return the view so `@foreach (var group in Model.Memberships)` will also throw an exception. –  Oct 27 '15 at 21:42
  • A better approach would be to generate a checked list box of all groups so that you can select and un-select groups as required - refer [this answer](http://stackoverflow.com/questions/29542107/pass-list-of-checkboxes-into-view-and-pull-out-ienumerable/29554416#29554416) for an example –  Oct 27 '15 at 21:44
  • @StephenMuecke Thanks for the comments, I figured out why it wasn't working and posted my answer. I'm thinking of changing to checkboxes later but the point of the app is organization for really small groups (maybe 20 people managed at a time) and each member would only be *perhaps* 2 or 3 subgroups, and *usually* only in one. I do need to stop it from adding members to groups they are already in, though! – queenofgoats Oct 28 '15 at 19:20

1 Answers1

0

Solved it...

group.Members was null so group.Members.Add(person) didn't work. Wrote in an if/else statement to instantiate a new member list if the list is null, and it works fine:

if (group.Members == null)
            {
                group.Members = new List<Person>();
                group.Members.Add(person);
            }
            else {
                group.Members.Add(person);
            }