ASP.net MVC: Creating SelectList in the view or action?
Asked Answered
N

5

5

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

Neutrophil answered 8/2, 2010 at 1:36 Comment(0)
S
5

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.

Soutine answered 8/2, 2010 at 1:37 Comment(6)
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?Pursuant
@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.Soutine
@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 :)Pursuant
@Seth: Quite true. At the time, I only had time to answer the question without the discourse. Thanks for reminding me.Soutine
You can't have a SelectList property as part of your strongly-typed ViewModel because it will throw a "no parameterless constructor" error".Anvers
@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.Soutine
S
2

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.

Sooty answered 8/2, 2010 at 11:26 Comment(4)
You still have to create a list of items in your ViewModel, so why not just make it a SelectList?Soutine
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.Sooty
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.Pursuant
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.Sooty
O
1

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.

Oconnell answered 8/2, 2010 at 4:37 Comment(2)
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.Soutine
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.Oconnell
F
1

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.

Foreword answered 8/2, 2010 at 7:49 Comment(2)
"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.Soutine
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).Foreword
M
0

Neither, create it in a separate class, look here How to map View Model back to Domain Model in a POST action?

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

Minnie answered 5/5, 2010 at 18:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.