1

This should be really easy, and I can't for the life of me realize what I haven't found any answers to this despite at least an hour of Googling. Anyway, here we go:

I want to create a simple ASP.NET MVC view with some dropdowns that allow the user to select some values, that are then saved as ID:s to the database. As I've been told that ViewBag/ViewData is the devils work I've tried to solve this by adding a selectlist to my (View)Model like:

public virtual SelectList Accommodations { get; set; }

and then in my controller fill it up with something like:

LoanApplication theLoanApplication = new LoanApplication();
            theLoanApplication.Accommodations = new SelectList(db.Accommodations.ToList(), "AccommodationID", "Name");

and finally in my view use this to get it all working:

@Html.DropDownListFor(model => model.AccommodationID, Model.Accommodations, "Choose Accommodation")

This works as it should, but when i try to save the model, I get errors that the Accommodations property (the list) is null which is kind of expected. Everything else in my model is as it should though.

I've looked at the well known "Countoso University" code example on the ASP.NET site and in it they seem to use ViewBag to solve similar problems. Is it so that ViewBag isn't all that bad to use in a scenario like that and that it might even be the best possible solution? If not, what would the prefered way be to solve this problem and not use ViewBag/ViewData?

Thank you.

ImproWise
  • 21
  • 4
  • show your Controller code – Ehsan Sajjad Jun 13 '15 at 20:39
  • Using a view model is always better than `ViewBag`. Why would you expect the `Model.Accommodations` to be populated (and using `ViewBag` will certainly not populate it anyway). You don't (and should not) be generating inputs for each property of each `SelectListItem` in the collection. If you need to return the view because `ModelState` is invalid, then you reassign the `SelectList` to property `Accommodations` before you return the view. –  Jun 14 '15 at 00:12
  • @Stephen It was expected that the Accommodations would be null (ie not populated) as those are only lookup values. Because they are lookup values, I only want to save the actual selected ID, not the loopup values (for obvious reasons). The problem is that I don't know how to provide the lookup values to the view using my model instead of ViewBag but still not make them part of the SaveChanges(). I only want to save the ID of the selected item in the dropdown. Sorry if my OP was unclear. – ImproWise Jun 14 '15 at 12:19
  • Not sure I understand - why would you save the `SelectList` (or have you added that property to your data model? - in which case don't - in belongs in a view model) –  Jun 14 '15 at 12:21
  • @Stephen Well, that is the million dollar question :) They are not really part of the model so you are correct in that, but I only know of 2 ways to get the possible lookup values to the view, by using ViewBag or by using my model. Perhaps the answer to this is a simple as "use ViewBag to send Lookup values to the view". – ImproWise Jun 14 '15 at 12:25
  • A view should not use a data model. You should have view model which includes the `SelectList` property (the data model does not contain the `SelectList` property). In the controller initialize a new instance of the view model and send it to the view. In the POST method, innitialize a new instance of your data model and map the view model properties to it, then save the data model. See also [What is ViewModel in MVC?](http://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc) –  Jun 14 '15 at 12:29
  • @Stephen Yes, that is probably the best solution and the most likely to be used once you go N-tier. I'm currently experimenting a bit with a quick & dirty 1 layer solution so the viewmodel and datamodel is the same but in a real business application that hopefully wouldn't be the case. Thanks for your suggestion. – ImproWise Jun 14 '15 at 13:25
  • I think you can see an example here: http://www.codeproject.com/Articles/702890/MVC-Entity-Framework-and-Many-to-Many-Relation – Amir Mahmoodi Jun 14 '15 at 21:13

1 Answers1

0

In your controller post action, simply reload the Accommodations list from the db as you do in the get action.

You'd normally do this if the modelstate has errors and you want to pass these back to the view, otherwise there's no need to reload the select list. You've not specified exactly where it gives null reference, so I'm assuming when you have modelstate errors and reloading the view to show the server-side errors. eg:

[HttpPost]
public ActionResult EditAccommodation(AccommodationViewModel model)
{
    if (!ModelState.IsValid) 
    {
        model.Accommodations = new SelectList(db.Accommodations.ToList(), "AccommodationID", "Name");
        return View(model);
    }

    // else modelstate ok and model.AccommodationID set 
    ...
}

As an aside, I recommend you keep the variable names clear, eg:

public virtual SelectList AccommodationSelectList { get; set; }

then, when you refer to Accommodations it's clear if it's the select list (which isn't really a list of accommodations, it's a list of select items) or the real list of accommodations from the database.

freedomn-m
  • 27,664
  • 8
  • 35
  • 57
  • Thank you for your answer. Perhaps I was unclear in my OP, sorry for that. I only want to save the ID of the selected item in the dropdown list. The other items are just lookup values. But I don't know how to provide the lookup values via the model but still make sure SaveChanges() does not try to save them to the database as part of the LoanApplication. As mentioned before, the ViewBag solution seem to be working fine, but I don't really like using ViewBag. – ImproWise Jun 14 '15 at 12:21
  • In the code above, the lookup values would not be loaded from the DB at time of save. You can easily replace 'viewbag' by creating a class specifically for the view (a viewmodel). This will work in exactly the same way as ViewBag but strongly typed. You might want to consider updating your question and adding `entity-framework` tag if the question is more around 'SaveChanges()' (or add your code for SaveChanges) as there's currently nothing in the question text regarding an issue with saving lookups. – freedomn-m Jun 14 '15 at 23:25