List of strings to DropDownListFor - asp.net-mvc

This is my model:
public class ContentPage
{
public BlogPost BlogPost { get; set; }
public List<BlogPost> BlogPosts { get; set; }
public List<string> Kategorier { get; set; }
}
I would like to use the values in the
public List<string> Kategorier { get; set; }
In a dropdownlistfor, this is what i got so far:
#Html.DropDownListFor(o => o.BlogPost.Kategori, "Here i want my list i guess?"(o => new SelectListItem { Text = o.Kategori, Value = o.Kategori }), "", null)
To clearify, I want to use the values in the List Kategorier in order to set the value for the o.BlogPost.Kategori
Any help appreciated.

There is a number of overloads you can use, but the one I find most readable is
#Html.DropDownListFor(model => model.BlogPost.Kategori,
Model.Kategorier.Select(kat => new SelectListItem { Text = kat, Value = kat })
Part of the reason why I like this overload is just that I prefer strong typing and being helped by the (aspnet) compiler. I generally avoid SelectList and its string-based constructors because they are brittle.
You may want to turn your List<string> into an IEnumerable<SelectListItem> in your view model instead of having to do it in the view.
EDIT:
I would do something like
public class ContentPage
{
public ContentPage(){} //Default constructor needed for model binding
public ContentPage(List<string> kategorier /* and possibly more arguments */)
{
Kategorier = kategorier.Select(k => new SelectListItem { Text = k, Value = k });
}
public BlogPost BlogPost { get; set; }
public List<BlogPost> BlogPosts { get; set; }
public IEnumerable<SelectListItem> Kategorier { get; set; }
}
Be aware that this should be fine for creating new blogposts, but if you want to edit existing blog posts, you will have to do a little more work (categories will have to be selected etc. when you render the page initially etc).

Related

Reference to the enum from model in Index view

I have a trouble with reference to my enum from model in Index view.
Here is my model's code:
public enum UnitOfMeasure {
Item,
Kilogram,
Liter, }
public class Product {
public Product() {
ProductOccurences = new List<ProductOccurence>(); }
[Key]
public int ProductId { get; set; }
public int ProductPhotoId { get; set; }
public UnitOfMeasure? UnitOfMeasure { get; set; }
public string ProductDescription { get; set; }
public virtual ProductPhoto Photo { get; set; }
public virtual ICollection<ProductOccurence> ProductOccurences { get; set; } }
In Index view I have search fields for filtering specific results. You can also search for UnitOfMeasure value (I use #Html.EnumDropDownListFor) - but I can't refer directly to the enum field from my model - because my view is strongly typed:
#model IEnumerable<Models.Product>
To show this field with the values of the selection I use the trick:
#Html.EnumDropDownListFor(model => model.FirstOrDefault().UnitOfMeasure, "Select unit of measure")
but it's terrible and ugly solution - also with unwanted value loaded by default.
What is the most elegant way to solve this issue in my situation?
You can use EnumHelper like this:
#Html.DropDownList("UnitOfMeasure", EnumHelper.GetSelectList(typeof(UnitOfMeasure)))
OR
You can do like this for strongly typed view:
#{ // you can put the following in a back-end method and pass through ViewBag
var selectList = Enum.GetValues(typeof(UnitOfMeasure))
.Cast<UnitOfMeasure>()
.Select(e => new SelectListItem
{
Value = ((int)e).ToString(),
Text = e.ToString()
});
}
#Html.DropDownListFor(m => m.UnitOfMeasure, selectList)

ModelState.IsValid with DTO and Entity Framework code first

ASP.NET 4.5, MVC 5, EF6 code first
I'm a newbie and probably asking something long-known but I couldn't find solution on the web, probably because I don't know correct terminology to formulate this question.
To simplify things, let's say I have two model classes Teacher and Kid; One kid can be assigned only to one teacher, but one teacher can have many kids. As I'm using code first, my database is constructed from these model classes:
public class Kid
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public virtual Teacher { get; set; }
}
public class Teacher
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public virtual ICollection<Kid> Kids { get; set; }
}
Now, I need to have a view for adding new kid with:
Textbox for Kid's name;
Dropdown with list of Teachers
So, I'm creating a data transfer object, specifically for that view:
public class AddNewKidViewDTO
{
public IEnumerable<SelectListItem> Teachers { get; set; }
public int SelectedTeacherId { get; set; }
public Kid Kid { get; set; }
}
I also have a method for populating IEnumerable Teachers:
public AddNewKidViewDTO LoadTeachersForDropDownList()
{
... //get the list of Teachers
AddNewKidViewDTO addNewKidViewDTO = new AddNewKidViewDTO();
List<SelectListItem> selectListItems = new List<SelectListItem>();
foreach (teacher in Teachers)
{
selectListItems.Add (new SelectListItem
{
Text = teacher.Name.ToString(),
Value = teacher.Id.ToString()
});
}
addNewKidViewDTO.Teachers = selectListItems;
return addNewKidViewDTO;
}
and in the view AddNewKid.cshtml
<form>
#Html.LabelFor(model => model.Kid.Name)
#Html.TextBoxFor(model => model.Kid.Name, new {id ="Name"}
<br/>
#Html.LabelFor(model => model.Kid.Teacher)
#Html.DropDownListFor(model => model.SelectedTeacherId, Model.Teachers)
</form>
Form gets submitted and in the controller I get my populated AddNewKidViewDTO model:
[HttpPost]
public ActionResult SaveNewKid (AddNewKidViewDTO addNewKidViewDTO)
{
if (ModelState.IsValid)
{
//here is where the problem comes
}
}
ModelState.IsValid in my case will always return false.
Because when it starts validating AddNewKidViewDTO.Kid, Teacher is compulsory field but in my addNewKidViewDTO model it's null. I have the necessary teacher Id contained in addNewKidViewDTO.SelectedTeacherId only.
My question is, what is an elegant way to validate my model before passing to my inner business logic methods?
Any help is appreciated.
There are multiple possible solutions:
Changing your AddNewKidViewDTO and decorating it with the DataAnnotaions for validation:
public class AddNewKidViewDTO
{
public IEnumerable<SelectListItem> Teachers { get; set; }
[Range(1, 2147483647)] //Int32 max value but you may change it
public int SelectedTeacherId { get; set; }
[Required]
public string KidName { get; set; }
}
Then you can create Kid object manually in case that your model valid.
UPDATE (to address your comment)
If you use this approach your action will look like this:
[HttpPost]
public ActionResult SaveNewKid (AddNewKidViewDTO addNewKidViewDTO)
{
if (ModelState.IsValid)
{
using (var dbContext = new yourContext())
{
var teacher = dbContext.Teachers.FirstOrDefault(t=>t.id == addNewKidViewDTO.SelectedTeacherId );
if(teacher == default(Teacher))
{
//return an error message or add validation error to model state
}
//It is also common pattern to create a factory for models
//if you have some logic involved, but in this case I simply
//want to demonstrate the approach
var kid = new Kid
{
Name = addNewKidViewDTO.KidName,
Teacher = teacher
};
dbContext.SaveChanges();
}
}
}
Write a custom model binder for AddNewKidViewDTO that will initialize Teacher property in Kid object so once you actually use Model.IsValid the property will be initialized.

MVC Drop Down list with entity framework

I've created an MVC project using entity framework code first. My model is simply a form that gathers information.
public class Application
{
public int Id { get; set; }
public string FirstName { get; set; }
public string MiddleInitial { get; set; }
public string LastName { get; set; }
public int SSN { get; set; }
public DateTime DOB { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State {get; set; }
public string Zip { get; set; }
public int HomePhone { get; set; }
public int BusinessPhone { get; set; }
public int MobilePhone { get; set; }
}
My goal is to create a drop down list with all of the states, but I'm finding this to be very difficult given that I've already created the database via scaffolding with views and controllers. Is there a simple way to do this and tie it in with the existing database? I've searched for almost the entire day with no luck. An overview/explanation of what to include for the model/controller/view would be amazing!
Update: I've created a new model named "State" with properties "Id" and "StateName" and have created some states in the database. In my "Application" controller inside the Create action method I have:
Controller
public ActionResult Create()
{
ApplicationDbContext db = new ApplicationDbContext();
this.ViewData["Id"] = new SelectList(db.States.ToList(), "Id", "StateName");
return View();
}
View
#Html.DropDownList("Id")
Now the problem is I'm getting this error " There is no ViewData item of type 'IEnumerable' that has the key 'Id'." Would really appreciate help!
Its quite simple. Add an IEnumerable<SelectListItem> property to your model(Here I suggest you make a ViewModel that can have the exact same properties as Application with the below code included as a property). Then you just need to build the list and send it to your view
public IEnumerable<SelectListItem> States{ get; set; }
I will assume you want to retrieve the State values from the db. Here is how you will do it:
private IEnumerable<SelectListItem> GetAllStates()
{
IEnumerable<SelectListItem> list = from s in db.Applications
select new SelectListItem
{
Selected = false,
Text = s.State,
Value = s.State
};
return list;
}
Or this...
private IEnumerable<SelectListItem> GetAllStates()
{
IEnumerable<SelectListItem> list = db.Applications.Select(s => new SelectListItem
{
Selected = false,
Text = s.State,
Value = s.State
});
return list;
}
Then do something like this in your action:
var app = new Application
{
States = GetAllStates()
};
return View(app);
Then finally, use Razor on the view to display the Dropdown list like this
#Html.DropDownListFor(m => m.State, Model.States, "--Select a State--")
The 1st parameter is the property of the model to update, the 2nd is the list of data, and 3rd is the default message that will be displayed
Hope this helps.
Create a data layer that retrieves a list of what you want. Then use EF to get all the states.
//assuming you have a table of states..
var states = db.States();
The states table should be a Unique list of states.
var selectList = new List<SelectListItem>();
foreach(var thing in states){
//if you got everything, thus the ID field for the value...
selectList.Add(new SelectListItem {Text =thing.State, Selected = false, Value = thing.ID);
}
Make sure in your Viewmodel class that selectlist is a public property.....and set to what you did above. You also need to provied a string for the view selection post back.
StatesSelectList = selectList;
public IEnumberable<SelectListItem> StatesSelectList {get;set;}
public string SelectedState {get;set;}
In your view, do this:
#Html.DropDownListFor(p=>Model.SelectedState, Model.StatesSelectList)
Very simple Code step by step
1) In Entity Framework Class
var productsList = (from product in dbContext.Products
select new ProductDTO
{
ProductId = product.ProductId,
ProductName = product.ProductName,
}).ToList();
2) In Controller
ViewBag.productsList = new EntityFrameWorkClass().GetBusinessSubCategoriesListForDD();
3) In View
#Html.DropDownList("Product_ProductId", new SelectList(ViewBag.productsList, "ProductId", "ProductName"), new { #class = "form-control" })
OR
#Html.DropDownListFor(m=>m.Product_ProductId, new SelectList(ViewBag.productsList , "ProductId", "ProductName"), new { #class = "form-control" })
I assume there is a States model that has a Id and a StateName property.
Change to the list to ViewData["State"] to ensure easy binding on POST.
Id is the value that will be sent in the POST data ie.. State = Id. The StateName is what will be displayed in the Select list. So for your model this is not correct as State is a string. So needs to be
this.ViewData["State"] = new SelectList(db.States.ToList(), "StateName", "StateName");
Then in your view
#Html.DropDownList("State")

How to get multiselected Dropdownlist values in asp.net mvc

I have a problem to get multi select dropdown list values.can anyone suggest me how to get select multiple dropdownlist values as well as how to get them in controller.
My code is like this:-
Model
public string BusinessUnitSiteSafetyRepresentative { get; set; }
Controller
[HttpPost]
public ActionResult AddClientBusinessUnitSite(LocalAddClientBusinessUnitSite local)
{
var query = from o in entitydb.systemusersorganizations.toList()
from c in entitydb.contacts.toList()
where o.orgId == clientId
select new SelectListItem
{
Text = c. Name;
Value = c.OrgId.toString()
}
ViewBag.list1 = query.ToList();
}
Well, I can get if single value is selected & can save to DB.But how to select multiple values as well as to get them in Controller so as to save them.
Note: - I am retrieving the dropdownlist values from DB as shown above.
View
#Html.ListBoxFor(x => Model.BusinessUnitSiteSafetyRepresentative,new
MultiSelectList((IEnumerable<SelectListItem>)#Viewbag.list1)
I have gone through some examples but none of them helped me.Please help me.
What I suggest is that your model needs to have a one to many relationship with the items in your multi select list.
An example is a Blog with multiple tags:
Your blog model may look like:
public class Blog
{
public Blog()
{
Tags = new List<Tag>();
}
public string BlogTitle{ get; set; }
public string Body{ get; set; }
public virtual ICollection<Tag> Tags{ get; set; }
}
And your tag model like so:
public int TagID{ get; set; }
public string TagName{ get; set; }
public virtual ICollection<Blog> Blogs{ get; set; }
Now I recommend you use a view model:
public class BlogViewModel
{
public Blog blog{ get; set; }
public List<int> SelectedTags { get; set; }
public virtual List<Tag> Tags{ get; set; }
public BlogViewModel()
{
}
public BlogViewModel(Blog _blog, List<Tag> _Tags)
{
blog = _blog;
Tags = _Tags;
SelectedTags = new List<int>();
}
}
And finally in your View (which inherits from the ViewModel);
#Html.ListBoxFor(m => m.SelectedTags,
new MultiSelectList(Model.Tags, "TagID", "Tag")
, null)
The JQuery Chosen plugin is excellent for this http://harvesthq.github.io/chosen/. You can use it by:
#Html.ListBoxFor(m => m.SelectedTags,
new MultiSelectList(Model.Tags, "TagID", "Tag")
, new { #class = "chzn-select", data_placeholder = "Tags..." })
Replace this with your own model and controllers and this should solve your problem. Also, this will work in your form for creating a new blog post, and for editing an existing post (adding and removing tags)
edit:
In your Blog Create controller action, you would populate this as:
public ActionResult Create()
{
var blog = new Blog();
var AllTags = from t in db.Tags
select t;
BlogViewModel viewModel = new BlogViewModel(blog,
Tags.ToList());
return View(viewModel);
}
public ActionResult Create(BlogViewModel blogViewModel)
{
Blog blog = blogViewModel.blog;
if (blogViewModel.SelectedTags != null)
{
foreach (var TagID in blogViewModel.SelectedTags)
{
Tag tag = db.Tags.Where(t => t.TagID == TagID).First();
blog.Tags.Add(tag);
}
}
db.Blog.Add(blog);
db.SaveChanges();
}
Try to change your modelproperty to a list type to accept multiple values:
public IEnumerable<string> BusinessUnitSiteSafetyRepresentative { get; set; }
Good answer by EvoNet. Its a different approach but worked well for me.
Here is Microsofts official way to do it: http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/creating-a-more-complex-data-model-for-an-asp-net-mvc-application
Search for:
A join table is required in the database, however, as shown in the following database diagram:
I tried it and yes it created the table but I had to start editing the controller to get it to write to the table. Then I also had to think about creating cases for when a relationship already exists etc.
So I reveted to this method which worked just fine for me.

Building a DropDownList in the Model?

I have a service layer that exposes a method, which returns me a List, called GetStates.
public List<StateObject> GetStates()
My State Object is just a custom object I have created:
public class StateObject
{
public int stateId { get; set; }
public string description { get; set; }
public Boolean isDefault { get; set; }
}
In my models, I am trying to create a model that will be used for my display and modification screen of a task. One thing this will be used for is handling the display and selection of a Drop down box, which will give a list of States available for my Task. So, my model looks something like this (Removed properties we don't car about - it's a bit bigger than this:
public class TaskModifyModel
{
public int stateId { get; set; }
public string state { get; set; }
public SelectList states { get; private set; }
public TaskModifyModel()
{
states = new SelectList(
(new ReferenceService().GetStates()),
"stateId",
"description",
1);
}
}
So, stateId holds the selected state, state holds the text description of the selected state. In the constructor, I am attempting to create a states SelectList for the view... and populate it.
In the view, I then try to display the Drop Down List:
#Html.DropDownListFor(m=>m.stateId, new SelectList(Model.states, "stateId", "description", Model.priorityId))
This is failing, dismally.
DataBinding: 'System.Web.Mvc.SelectListItem' does not contain a property with the name 'stateId'.
I have searched, and I thought I was doing this the right way, but the error says I am not.. clearly. :) Could someone guide me on why it's not working, and also, is this the right way to do things?
Edit:
After assistance below, it's now working. If I am creating a new task (taskId==0), then I have to get the default value of the dropdown, as stored in my database.... So, is this clean? This is my working constructor for the object:
public TaskModifyModel()
{
var referenceService = new ReferenceService();
var p = referenceService.GetPriorities();
var s = referenceService.GetStates();
var defaultP = (from a in p where a.isDefault select a).FirstOrDefault();
var defaultS = (from a in s where a.isDefault select a).FirstOrDefault();
priorities = new SelectList(
(p),
"priorityId",
"description"
);
priorityId = taskId == 0 ? defaultP.priorityId : priorityId;
states = new SelectList(
s,
"stateId",
"description");
stateId = taskId == 0 ? defaultS.stateId : stateId;
}
Is it OK?
Your public SelectList states { get; private set; } is already a SelectList so you don't need to cast it again in your View.
Try this instead:
#Html.DropDownListFor(m=>m.stateId, Model.states)
And in your ViewModel, remove the parameter "SelectedValue". The #Html.DropDownListFor will initialize the dropdown to the right value.
public class TaskModifyModel
{
public int stateId { get; set; }
public string state { get; set; }
public SelectList states { get; private set; }
public TaskModifyModel()
{
states = new SelectList(
(new ReferenceService().GetStates()),
"stateId",
"description");
}
}

Resources