MVC DropDownListfor() Basics - c#

I have a Model which consist of Employees information. In my model there is a property called City which define the city of Employee in which he lives. The propery is shown below
public string City{get;set;}
Now I have a view which contains a form which will be filled by a employee to register. I want to use a dropdownlist for selecting cities. I think the below code will be used for dropdown as i discovered. My model name is Employee.
#Html.DropDownListFor(m=>m.City,new SelectList())
Please tell me that "is there any way to define the options for dropdownlist in SelectList() method directly Like ... in html?"
If not, where should i define the class for this drop down, where to call and where to render.I don't know where to define values? I am very confused because this is mvc and we have to seperate concern and i think we cannot define anything at anywhere?
Thanks in advance..

You have at least two options:
1.) Add a list, array, or any other collection type of cities to your model
2.) Add a SelectList property to your model
Option 1 can be something as simple as an array of strings, or can be, say, an IEnumerable of City objects. You would then need to transform this property to a collection of SelectListItem objects in the view as part of the DropDownList binding.
Option 2 has the advantage of being capable of direct binding to the DropDownList, but requires that you construct the list within the action method.
Then end result is the same, it's just a matter of how pedantic you want to be about SoC.
For example (assuming you add a property called Cities):
#Html.DropDownListFor(m=>m.City, Model.Cities.Select(city => new SelectListItem()
{
Text = city,
Value = city,
Selected = city == Model.City
})
EDIT:
To answer your comment, I have to make some assumptions. I will assume you have a model called EmployeeModel. This model has a property, City, that is a plain string. So, this is a partial of your model, as I assume it to be:
public class EmployeeModel
{
public string City { get; set; }
// ... other properties ...
}
So, if you need to add a property for binding to your dropdown, you would do one of the following:
public class EmployeeModel
{
public string City { get; set; }
public IEnumerable<string> Cities { get; set; }
// ... other properties ...
}
or
public class EmployeeModel
{
public string City { get; set; }
public SelectList Cities { get; set; }
// ... other properties ...
}
This new property will contain the list of cities that you allow your user(s) to pick from.
If you choose the first option, you load the IEnumerable from your datastore, and then use the first example above in your view, which uses LINQ to project each string in the Cities property into a new SelectListItem object.
If you go with the second option, you build a SelectList in the action prior to passing the model to the view. This isn't terribly difficult, as the class provides a constructor that takes an IEnumerable (your list of cities) and the "selected value," which will be the City property (see http://msdn.microsoft.com/en-us/library/dd460123%28v=vs.108%29.aspx). Your code would look something like:
model.Cities = new SelectList(GetCities(), model.City);
This, of course, assumes you have a helper method (GetCities()) to load your cities from wherever they are stored. Your view then would have something like this:
#Html.DropDownListFor(m=>m.City, model.Cities)
The view engine then uses these SelectListItems to build the <select> element and it's <option> elements.

You could have this in your model, it's quickly achieved, although I wouldn't recommend it:
public class Place
{
public string City{get;set;}
public SelectListItem[] Cities()
{
return new SelectListItem[2] { new SelectListItem() { Text = "London" }, new SelectListItem() { Text = "New York" } };
}
}
...and your view
#Html.DropDownListFor(m => m.City, Model.Cities())
I think the best place for something like this (but is a little more complicated) is your own htmlhelper and usage could look something like:
#html.CityDropDownFor(m => m.City)
You could cache the cities nicely and it keeps data and UI work out of your models.
If you want to learn more about creating your own helpers, I'd suggest a bit of a [read up].1

Related

View logic or not for Drop Down list?

I'm developing a ASP.NET MVC application. I have following class:
public class Organization {
// Organization ID
public int Id {get; set;}
// Organization name
public string Name {get; set;}
// City where organization is located
public string CityName {get;set;}
}
This class is using in Model:
public class OrganizationsModel {
public Organization[] Organizations { get; set; }
}
In a view I want to render drop down list for picking an organization:
#Html.DropDownList("org", Model.OrganizationsList.Select(x => new SelectListItem { Value = x.Id, Text = String.Format("{0} ({1})", x.Name, x.CityName) }))
I have some fear about this:
new SelectListItem { Value = x.Id, Text = String.Format("{0} ({1})", x.Name, x.CityName) }
Is the view is wrong place for combining text for each option in drop down list? Maybe I should place this code to view model or controller? Looks like current code breaking MVC paradigm.
The code you're performing in the view is only related to creating display elements, so the view seems the right place to do that. You don't want to create SelectListItem, a class only related to display, in your model or controller.
From my point of view thats perfectly okay. The view is tailored to the gui needs. If you can push the concatenated information into the view without creating a model fields, that's fine.
You can also just place a property with only a getter:
public string GetCombinedName {
get {
return String.Format("{0} ({1})", this.Name, this.CityName);
}
}
On the Organization model. Or split it out on a OrganizationViewModel with this property on.
I also agree that this is completely fine in the view, but what I would say is that you should ensure that if this logic is required in multiple views, you shouldn't repeat the logic in another view, you should push it up into shared logic, such as in your business layer, or into a Html helper.

Class design best way to handle multi-value options and the selected value?

What's the best way to design a class (or classes) that can hold the potential values of item, as well as the one the user actually selected? I've come across this problem before and always feel like I'm missing a core class design feature.
Right now I usually do something like the following
class MultiChoice
Name (I.e. Box Size)
Default Value ("22x15")
PotentialValues ({"10x10","20x20","22x15"})
But that doesn't handle the actual value the user selected, so I add that in.
class MultiChoice
Name (I.e. Box Size)
Default Value ("22x15")
PotentialValues ({"10x10","20x20","22x15"})
SelectedValue
That doesn't feel right though, because when I construct a drop-down I'm filling in stuff with SelectedValue = null. Then when I store the data, I'm storing all the options too, which I don't need.
Is there a better way to handle this with an interface or other language construct? I always feel like I'm missing something blatantly obvious here.
You really have two separate entities here:
MultiChoiceQuestion
MultiChoiceAnswer
Create two separate classes to represent these two separate concepts.
ASP.NET MVC has the SelectList class. While you might not actually be working in ASP.NET MVC, it seems clear that Microsoft felt that the concept of "backing class for a dropdown" was universal enough to warrant its own class.
In whatever you consider the "Model" (that part of your program containing the business domain classes and business logic), there will always exist database tables that serve as lookups for these dropdowns.
tblCountries
CountryID PK
CountryCode string
FullName string
In your ViewModel, there will be a corresponding list of countries from which you can populate the dropdown:
public class InvoiceViewModel
{
...
public int CountryID { get; set; }
public SelectList Countries { get; set; }
// or
public List<Country> Countries { get; set; }
...
}
Of course, by the time you get to the UI, the actual dropdown contains enough plumbing to hold both the select list and the selected value.
You really only need a single Value field. Set it to whatever you want in the constructor (so it's defaulted when the object is created). You can also change your 'potential values' to be static, so it's the same for the entire class.
public class Box
{
public string Value { get; set; }
public static List<string> AllowedValues { get; private set; }
public Box()
{
AllowedValues.AddRange(new string[]{"10x10","20x20","22x15"});
Value = AllowedValues.First();
}
}
Then when a user changes the value, simply update it.
Box thisBox = new Box();
string val = "22x15";
if (Box.AllowedValues.Contains(val))
thisBox.Value = val;

How can I return an empty list instead of a null list from a ListBoxFor selection box in Asp.net MVC?

controller get action
IList<InputVoltage> inputVoltagesList = unitOfWorkPds.InputVoltageRepository.GetAll.ToList();
pdsEditViewModel.InputVoltageList = inputVoltagesList.Select(m => new SelectListItem { Text = m.Name, Value = m.Id.ToString() });
ViewModel
public IEnumerable<SelectListItem> InputVoltageList { get; set; }
public List<int> SelectedInputVoltages { get; set; }
View
#Html.ListBoxFor(m => m.SelectedInputVoltages, Model.InputVoltageList)
I want to receive a null list when a user makes no selections the selectedInputvoltages comes into my post controller action as null how do I get it to come in as an empty list?
I like both answers is there any benefit in using one over the other?
Either make sure it is initialized in the controller (or model/viewmodel) if null, or perhaps (ugly code though) use the coalesce operator to initialize on the fly if null:
#Html.ListBoxFor(m => m.SelectedInputVoltages, Model.InputVoltageList ?? new List<SelectListItem>())
If you initialize the list in the view model's constructor then it will always be at least an empty list. Anything which builds an instance of the view model would continue to set the list accordingly.
public class SomeViewModel
{
public List<int> SelectedInputVoltages { get; set; }
public SomeViewModel()
{
SelectedInputVoltages = new List<int>();
}
}
This way it will never be null in an instance of SomeViewModel, regardless of the view, controller, etc.
If you always want the view model's property to have a default value, then the best place to put that is in the view model. If that logic is instead placed in the controller or the view then it would need to be repeated any time you want to use it.

Simple DropDownList in MVC3

Working on my first MVC3 app. I have a simple View that has 2 objects (object A, object B). Object B is optional. I've created a Model with both objects and have the Controller working just fine passing the data back and forth to the View.
I'm trying to put in a simple DropDownList for the user to decide whether they want to enter data for object B. The dropdown list is simple - two values "Yes" and "No".
Ex: Continue with Part "B"?
[Yes]
[No]
On the View, the user fills out all of the form items of object A. Then, they have a choice to fill out the items of object B. I want them to select "Yes" if they want to do that (I'm using Jquery to show more of the page at that time).
My question: How do I make a simple Dropdownlist (or even a basic HTML input type="select"...) that I can access in the Controller after they submit the form?
In my Controller, I want to do the following:
* Do stuff for object A
* Check to see if they selected Yes
* Do stuff for object B
Does something as simple as a Yes/No dropdown need to go into the Model? Its not typed to anything - its just a decision made by the user in the View. I know there has to be a simple way of doing this (ViewBag?) but I'm new and apparently lost.
TL;DR - How do I create as simple DropdownList on a View that I can access in the Controller?
The rule of thumb for getting values from the view back in the HTTPPOST for your object is to name the input controls id and name properties the same as the Models property name. An easy way to do this is to use Html helpers.
public class Model
{
public Model()
{
List<SelectListItem> options = new List<SelectListItem>();
options.Add(new SelectListItem { Value = true.ToString(), Text = "yes" });
options.Add(new SelectListItem { Value = false.ToString(), Text = "no" });
ContinueOptions = options;
}
public bool Continue { get; set; }
public IEnumerable<SelectListItem> ContinueOptions { get; set; }
}
In your View:
#Html.DropDownListFor(m => Model.Continue, Model.ContinueOptions)
In your Controller:
[HttpPost]
public ActionResult Edit(Model model)
{
bool continueOn = model.Continue;
}
Yes your drop down should be part of the model, otherwise the controller won't have the answer from the user to Check to see if they selected Yes.
public SomeViewModel
{
public ObjectA A { get; set; }
public ObjectB B { get; set; }
public bool? IsBSelected { get; set; }
}
I usually use bool? simply because I like to know if the user selected on or the other, but using bool would be fine too.

MVC 3 2 models in a view

I am new to MVC (i.e. the last few days) and i would like to know if what i have done is the best way.
I have a view that is a combination of an insert item form with a list details form underneath for a particular entity. As such i kind of need 2 models for the page in order to avoid doing things like #Html.LabelFor(model => model.FirstOrDefault().EventTypeID, "Event Type").
What i have done is set the model to be Tuple<IEnumerable<Event>,Event> that way i have both the single item and the collection of items. Can anyone suggest a less hacky alternative or is this the best way of doing this?
There are 2 solutions.
You should create a different View Model Class (a simple class with both models as properties)
You can assign it to the ViewBag.Model1 ... ViewBag.Model2 ... But this is dynamic so you will have no intellisense and you can get errors at runtime.
You should use a ViewModel like this
public class ViewModel
{
public TypeOfYourModel MyModel1 { get; set; }
public TypeOfYourModel MyModel2 { get; set; }
}
I suggest you create a ViewModel that would contain both objects you want to pass.
public class NewEventViewModel
{
public Event NewEvent { get; set; }
public Event EventDetails { get; set; }
}
You could also use ViewBag, but it is not strongly typed so you would not get IntelliSense.
I would create a Model object just for the view, with 2 properties, one for the single entity and one for the collection, and then you can pass this composed object as the model for the view

Categories

Resources