2

I'm working on an application that uses a View Model to pass data to a view, however when I attempt to save changes the user makes to the data and post it back to the controller for processing and storing in a database, I'm getting null values for everything in my view model. I've tried various other questions on here and none of the answers I've found have been able to solve this issue. I think it has something to do with the my use of a ListBox to display some of the data, but I'm fairly new to ASP.net MVC 5 and am not quite sure what I need to be doing here.

Below is the code for my view model, the relevant sections from the controller, and the view.

View Model

public class OrganizationViewModel
{
    public Organization Organization { get; set; }
    public IEnumerable<SelectListItem> RelatedContacts { get; set; }
}

Sending Data from Controller to View

[HttpGet]
    public ActionResult Edit(Organization organization)
    {
        IEnumerable<SelectListItem> contactsList = GetContacts(organization);
        var viewModel = new OrganizationViewModel()
        {
            Organization = organization,
            RelatedContacts = contactsList
        };

        return View("Edit", viewModel);
    }

Receiving Data from View

[HttpPost]
    public ActionResult SaveOrganization(OrganizationViewModel organizationViewModel)
    {
        organizationViewModel.Organization.Id = (int)TempData["Id"];
        organizationViewModel.Organization.LastEdited = DateTime.Today;
        organizationViewModel.Organization.DateAdded = (DateTime)TempData["DateAdded"];
        TempData.Clear();
        if (ModelState.IsValid)
        {
            organizationRepository.SaveOrganization(organizationViewModel.Organization);
            return RedirectToAction("Index", "Organization");
        }

        IEnumerable<SelectListItem> contactsList = GetContacts(organizationViewModel.Organization);
        var viewModel = new OrganizationViewModel()
        {
            Organization = organizationViewModel.Organization,
            RelatedContacts = contactsList
        };
        return View("Edit", viewModel);
    }

The Edit View

<div class="panel">
<div class="panel-heading">
    <h3>Editing @(Model.Organization.Name)</h3>
</div>

@using (Html.BeginForm("SaveOrganization", "Organization", FormMethod.Post))
{
    <div class="panel-body">
        @Html.HiddenFor(m => Model.Organization.Name)
        <div class="row">
            <div class="col-md-3 form-group">
                <label>Organization Name</label>
                @Html.TextBox("Name", null, new { @class = "form-control" })
            </div>
            <div class="col-md-3 form-group">
                <label>Address</label>
                @Html.TextArea("Address", null, new { @class = "form-control" })
            </div>
        </div>
        <div class="row">
            <div class="col-md-3 form-group">
                <label>Related Contacts</label>
                @Html.ListBox("RelatedContacts", Model.RelatedContacts, new { @class = "form-control", size = 10 })
            </div>
            <div class="col-md-3 form-group">
                <label>Custom Fields</label>
                <br />
                <input type="button" value="Add New Field" class="btn btn-default" />
            </div>
        </div>
        <div class="row">
            <div class="col-md-12 form-group">
                <label>Notes</label>
                @Html.TextArea("Notes", null, 10, 500, new { @class = "form-control", @style = "width: 100%; max-width: 100%;" })
            </div>
        </div>
    </div>
    <div class="panel-footer">
        <input type="submit" value="Save" class="btn btn-primary" />
        @Html.ActionLink("Cancel and return to List", "CancelEditOrAdd", null, new { @class = "btn btn-default" })
    </div>
}

CthuluHoop
  • 136
  • 2
  • 15
  • 2
    Your generating `name` attributes in your form controls which have no relationship at all to your model. Always use the strongly typed methods - `@Html.TextBoxFor(m => m.Organisation.Name)` -- and then compare the `name` attributes in both cases to understand why you code does not work. –  Feb 21 '18 at 21:38
  • 1
    But view models do not contain data models when editing data. They contain the properties of your data model that you need in the view. Refer [What is ViewModel in MVC?](https://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc) –  Feb 21 '18 at 21:39
  • Thank you! That fixed part of the issue--I'm now getting data for the Organization in the view model upon postback, but still nothing for the related contacts. Currently I'm not using the ListBox to do anything more than display the data, eventually I'll be using the selections from that in a later implementation. – CthuluHoop Feb 21 '18 at 22:00
  • 1
    You have not shown your model, or what its properties are! And a ` –  Feb 21 '18 at 22:04
  • Aah, I get it now. I created a new property in the view model to correspond to the selected index and everything is working now. Thanks for your insight, I appreciate it! – CthuluHoop Feb 21 '18 at 22:15
  • 1
    The most important thing you need to do is change your view model. It will **not** contain your `Organization Organization` property. Instead it will contain a property for each property of `Organization` that your editing, plus the `IEnumerable` property) –  Feb 21 '18 at 22:18

1 Answers1

1

Answering my own question for anyone who stumbles across this and wants to see the exact changes I made based on @Stephen Muecke's comments.

Changed all the @html.something()s into @html.somethingfor()s for fixed the issue with not receiving postback data for the Organization in the View Model, and then I created a new property in the view model to correspond with the selected index in the ListBox, which now reads @Html.ListBoxFor(m => m.SelectedIndexes, Model.RelatedContacts, ...). I'm now getting all the proper postback data and can relate the selected index to the Organization's related contacts.

Edit: Also changed my View Model to contain the properties of my Organization class and not an actual Organization object itself as a property.

CthuluHoop
  • 136
  • 2
  • 15