views:

437

answers:

5

Hey guys

I'm just wondering where people are creating their SelectList - in the action or the view.

I have seen examples of both and the one that makes the most sense to me is doing it in the action and have the view model have a property of type SelectList.

On the other hand, I have seen examples where people have the view model have a property of SelectList and the SelectList is populated within the view model (either in the constructor or via lazy loading). I like this idea as it means there is less code in my actions...

In short I was just wondering what people are doing atm.

Cheers Anthony

+4  A: 

Create your SelectList in the controller (by looking up your list of items from your model repository), and pass it to the view as either a ViewData object, or as part of your strongly-typed ViewModel.

Robert Harvey
Why? I'd be happy to upvote if you provide some more detail on why you think this approach is preferable. Is it easier to test? Promote code reuse? Better separation of concerns?
Seth Petry-Johnson
@Seth: The purpose of a strongly-typed ViewModel object is to package up all of the data that is required by a view in order to render it properly. In this case, because a dropdown requires a list of items, it is appropriate to include it in the ViewModel object. The programmer coming after me will see the SelectList in the ViewModel, and conclude that it is being used to populate a dropdown in the view. And he doesn't have to look anywhere else.
Robert Harvey
@Robert: I completely agree with you. My point was that your answer was selected as the "correct" one, and I thought some additional information might be helpful to someone that comes across this question in the future. I'd rather new MVC programmers know _why_ this is preferable, instead of blindly following a SO answer :)
Seth Petry-Johnson
@Seth: Quite true. At the time, I only had time to answer the question without the discourse. Thanks for reminding me.
Robert Harvey
You can't have a SelectList property as part of your strongly-typed ViewModel because it will throw a "no parameterless constructor" error".
Aros
@Aros: Maybe, if you're trying to bind a form using the same strongly-typed view model, and the binder is trying to reflect over it. In this question, the context is providing a `SelectList` to a view so that a dropdown can be rendered. I have used this approach successfully before, without getting a "no parameterless constructor error." If the error ever occurred, you could simply provide a parameterless constructor.
Robert Harvey
+1  A: 

I typically create my SelectList in the action or service layer and pass it to my view via ViewData. I've also made it a part of a view model and a strongly typed view. Both ways create it in the action or service layer though.

DM
Passing SelectLists via ViewData is OK, but if your page is strongly typed to a ViewModel object, it's cleaner just to include your SelectLists as part of the ViewModel.
Robert Harvey
agreed, and that's what I do if need to send more data to the view than just the select list. If all I need is a select list then I tend to use ViewData.
DM
+1  A: 

I have the SelectList exposed as a property in the view model and populate it in the action using the necessary repository. I think that the code that interacts directly with the repositories should be the one that is also responsible with populating, be it the controller actions or service layer or whatever else.

I don't think that populating the list directly from the view model is a good idea, because it would require the view model to have a repository dependency and do database interactions and the view model should not be responsible for this kind of things.

You could also create a separate special object, called Initializer or something like that, that does all the populating and initializations, if you have multiple SelectList fields and want to keep your actions code cleaner.

Victor
"I don't think that populating the list directly from the view model is a good idea, because it would require the view model to have a repository dependency" - Not necessarily. The View Model is populated in the controller (including the list of items required for the SelectList), so no repository dependency is required in the View Model itself.
Robert Harvey
That was exactly my point. The repository populating code should be called from the controller, not from inside the view model code(the constructor or some other method).
Victor
+2  A: 

It´s a presentation-specific aspect, so I prefer to do it in the View, using an Html helper. So I pass a collection to the View and use a html helper method to map the items to SelectListItems. The method could look very much like this:

public static IList<SelectListItem> MapToSelectItems<T>(this IEnumerable<T> itemsToMap, Func<T, string> textProperty, Func<T, string> valueProperty, Predicate<T> isSelected)
{
    var result = new List<SelectListItem>();

    foreach (var item in itemsToMap)
    {
        result.Add(new SelectListItem
        {
            Value = valueProperty(item),
            Text = textProperty(item),
            Selected = isSelected(item)
        });
    }
    return result;
}

Regards.

uvita
You still have to create a list of items in your ViewModel, so why not just make it a SelectList?
Robert Harvey
You´re right, I was thinking of the model just as an entity or a dto translated from an entity (not as view-specific model or ViewModel), anyway, you could use the method above to make the translation.
uvita
I think that view-specific models should probably expose a SelectList directly, because it reduces the amount of code you have to write in the view, even if just a little. But in some cases I pass a DTO or business object to a view, and in those cases I'll call a helper like you show above [mine is called .ToSelectList()] from the view. I think both approaches are appropriate in different scenarios.
Seth Petry-Johnson
What I don't like about creating the SelectList in the Controller (or in an class that translates a BO to a ViewModel) is that sometimes you need to add dummy options as "Choose one" or "None", etc. If your application is going to be localizable, then you should pick this text from a resource file which is disturbing as it is something that affects the tests for that specific action.
uvita
A: 

Neither, create it in a separate class, look here http://stackoverflow.com/questions/2206005/how-to-map-view-model-back-to-domain-model-in-a-post-action/2775656#2775656

I use an IBuilder interface in the controller and do all the building of entities/viewmodels in the implementation of this Builder

Omu