I'm new to MVC, so bear with me...
I've got my new form\view working (Creating and Adding a client)
But now I want to get the user so specifiy the Country where the new client is from A drop downlist. But im to sure how I to do this?
ViewModel
public class ClientNew
{
public string Company { get; set; }
public string Address { get; set; }
//New
public IEnumerable<CountryList> Country{ get; set; }
}
public class CountryList
{
public string Id { get; set; }
public string Name { get; set; }
}
Controller
(This is where is may be wrong, and is this the best way to do it?)
public ActionResult New()
{
var cl= new List<CountryList>();
cl.Add(new CountryList(){Id = "abcd",Name = "UK"});
cl.Add(new CountryList() { Id = "abce", Name = "USA" });
var model = new ViewModels.ClientNew();
model.Country= cl;
return View("New", model);
}
View (not sure how to plumb this in)
Html.DropDownList("Id" ??????)
In your view you will set up your dropdown on the property Id. This will be the current value selected in the dropdown when you POST to your form. The data that will be used for the dropdown is a SelectList called Countries that exists in your model.
#Html.DropDownListFor(m => m.Id, Model.Countries)
Your view model will have your Id, Name and Countries properties plus whatever else you need.
public class ClientNewViewModel {
public string Id { get; set; }
public string Name { get; set; }
public SelectList Countries { get; set; }
}
In your controller you need to pass the model to the view. You will need to populate the Countries SelectList. Keep in mind you will need to populate this value when you POST and fail validation as well.
public ActionResult New()
{
var model = new ClientNewViewModel();
model.Countries = new SelectList(service.GetCountries(),
"Id", "Name"); // set up what properties are used for id/name of dropdown
return View(model);
}
[HttpPost]
public ActionResult New(ClientNewViewModel model)
{
if( !ModelState.IsValid )
{
model.Countries = new SelectList(service.GetCountries(),
"Id", "Name");
return View(model);
}
// redirect on success
return RedirectToAction("Index");
}
Html.DropDownList("Id",
Country.Select(x => new SelectListItem
{
Text = x.Name,
Value = x.Id
}));
There's a good blog post on the in's and out's of how to do this here -> http://277hz.co.uk/Blog/Show/10/drop-down-lists-in-mvc--asp-net
Related
I have an MVC 5 site, I would like to use a strongly typed DropDownListFor with a ViewModel - not with ViewBag.
I have found various articles on this - but they all seem to have huge holes - for example this one doesnt cover editing, and I do not understand how or when "SelectedFlavourId" should be used.
http://odetocode.com/blogs/scott/archive/2013/03/11/dropdownlistfor-with-asp-net-mvc.aspx
I have several requirements.
When editing the story I would like a drop down list of all places to
be displayed - with the associated place (if any) - selected.
I want to use the strongly typed DropDownListFOR (as opposed to
DropDownList).
I would like to use a ViewModel not the ViewBag.
I want to add a "No Associated Place" which will be
selected if PlaceId is null.
I want to add a css class = "form-control" to the DropDownListFor.
The below is as far as I have got after a day of frustration.
A story can be optionally associated with a PlaceId. A blank placeId is also valid. A place can also be associated with more than one story.
Models
public class Place
{
public Guid Id { get; set; }
public string PlaceName { get; set; }
}
public class Story
{
public Guid Id { get; set; }
public Guid? PlaceId { get; set; }
public string StoryName { get; set; }
}
public class StoryPlaceDropdown
{
public Story story { get; set; }
public Guid SelectedStoryId;
public IEnumerable<Place> places;
public IEnumerable<SelectListItem> placeItems
{
get
{
return new SelectList(places, "Id", "PlaceName");
}
}
}
Controller
public ActionResult Edit(Guid Id)
{
var spd = new StoryPlaceDropdown();
spd.places = PlaceRepo.SelectAll();
spd.story = StoryRepo.SelectStory(Id);
spd.selectedStoryID = apd.story.Id;
// Return view
return View(spd);
}
[HttpPost]
public ActionResult Edit(StoryPlaceDropdown spd)
{
// Never gets this far
spd.Places = PlaceRepo.SelectAll();
return View();
}
In View
#Html.DropDownListFor(m => m.SelectedStoryId, Model.PlaceItems)
This populates the DropDownList fine. However it does not select the correct item in edit view. Also when I submit the form I get this error:
Object reference not set to an instance of an object. on this line in the view #Html.DropDownListFor(m => m.SelectedStoryId, Model.PlaceItems)
How can I get this all working? Thanks.
I solved this - I had stupidly forgotten the { get; set; } accessors on the ViewModel, doh!
You can resolved this by these three steps:
Step 1:Create viewmodel
public class StoryPlaceDropdown
{
Required]
[Display(Name = "SelectedStory")]
public int SelectedStoryId { get; set; }
}
Step 2:After this on controller you can write:
public ActionResult Edit(Guid Id)
{
var spd = new StoryPlaceDropdown();
ViewBag.PlaceItems= PlaceRepo.SelectAll();
spd.story = StoryRepo.SelectStory(Id);
spd.selectedStoryID = apd.story.Id;
return View(spd);
}
Step 3: And on view you can write
<div class="col-sm-6">
#Html.DropDownListFor(m => m.SelectedStoryId, new SelectList(#ViewBag.PlaceItems, "Id", "PlaceName"), "---Select---", new { #class = "form-control select-sm" })
</div>
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")
I am trying to include a list of Clients in a drop down box. I am including this list in a form (the Html.BeginForm()) so that I can pass the selected value to my POST controller. I think I am missing something, I have the following classes:
my Invoice ViewModel:
public class InvoiceViewModel
{
public InvoiceViewModel()
{
// makes sure InvoiceItems is not null after construction
InvoiceItems = new List<PrelimInvoice>();
}
public List<PrelimInvoice> InvoiceItems { get; set; }
public List<Client> ClientId { get; set; }
public Client Client { get; set; }
public decimal InvoiceTotal { get; set; }
}
My Client Model:
public class Client
{
public string ClientId { get; set; }
public string Name { get; set; }
}
My SaveInvoice method:
public ActionResult SaveInvoice()
{
var invoice = new Invoice();
TryUpdateModel(invoice);
try
{
invoice.ClientId = User.Identity.Name;
invoice.DateCreated = DateTime.Now;
//Save invoice
proent.Invoices.Add(invoice);
proent.SaveChanges();
//Process the invoice
var preliminvoice = InvoiceLogic.GetInvoice(this.HttpContext);
preliminvoice.CreateInvoice(invoice);
return RedirectToAction("Complete", new { id = invoice.InvoiceId });
}
catch
{
//Invalid - redisplay with errors
return View(invoice);
}
}
And my Index.cshtml is strongly typed to the InvoiceViewModel class.
Index.cshtml is where I generate the form.
I am not sure of the code for creating the Html.DropDownList, and whether or not I need to include a List or something of my Clients. I have dropdownlists in other places but they are strongly typed to models, not viewmodels, hence my confusion.
Can anyone assist me?
Start by adding to your ViewModel the following 2 properties:
SelectedClientId: which stores the selected value
ClientItems: stores the collection of SelectListItems which populates your drop down.
E.G.
public class ClientViewModel
{
public List<Client> Clients;
public int SelectedClientId { get; set; } // from point 1 above
public IEnumerable<SelectListItem> ClientItems // point 2 above
{
get { return new SelectList(Clients, "Id", "Name");}
}
}
Then on your View index.cshtml you would add the following:
#model ClientViewModel
#Html.DropDownListFor(m => m.SelectedClientId, Model.ClientItems)
I am using MVC-Viewmodel with repository pattern with EF on my project.
I have 3 tables, Question, CoreValue, SubjectType.
SubjectType and CoreValue are many to many associated with Question and these two tables are not suppose to get any new values, but users can create questions so Question table will get new data when a user creates it. I use two dropdownlists for CoreValue and SubjectType so that the user can choose a CoreValue and a SubjectType when they create a Question.
Here is my HTTPGET controller action:
// GET: /Admin/Create
public ActionResult Create()
{
CoreValueRepository Crep = new CoreValueRepository();
SubjectTypeRepository Srep = new SubjectTypeRepository();
CreateViewModel model = new CreateViewModel();
List<SubjectType> subjectypes = Srep.getall();
List<CoreValue> corevalues = Crep.getall();
model.SubjectTypes = new SelectList(subjectypes, "SID", "Sname");
model.CoreValues = new SelectList(corevalues, "CID", "Cname");
return View(model);
}
And here is my Viewmodel:
public class CreateViewModel
{
public string QuestionText { get; set; }
public string Sname { get; set; }
public string Cname { get; set; }
public SelectList SubjectTypes { get; set; }
public SelectList CoreValues { get; set; }
}
I use Repository for CRUD operations and viewmodels for handling data in UI.
Now I have to code the HTTPPOST Action Create in my controller for inserting Question data to my database, and the questions need to be tagged with CoreValue ID and SubjectType ID. So I was thinkin about to start coding the HTTPOST action Create, and I was wondering if someone could help me out with this.
Thanks in advance!
Best Regards!
This is how i would handle it :
In your ViewModel, replace :
public class CreateViewModel {
public string QuestionText { get; set; }
public string Sname { get; set; }
public string Cname { get; set; }
public int SubjectTypesID { get; set; }
public int CoreValuesID { get; set; }
}
In your HTTPGET put your list in Viewbags :
public ActionResult Create()
{
CoreValueRepository Crep = new CoreValueRepository();
SubjectTypeRepository Srep = new SubjectTypeRepository();
CreateViewModel model = new CreateViewModel();
ViewBag.SubjectTypes = Srep.getall();
ViewBag.CoreValues = Crep.getall();
return View(model);
}
To use the viewbag in your view you can use this :
#Html.DropDownList("SubjectTypesID ", new SelectList(ViewBag.SubjectTypes as System.Collections.IEnumerable, "SID", "Sname", Model.SubjectTypesID ))
#Html.DropDownList("CoreValuesID ", new SelectList(ViewBag.CoreValues as System.Collections.IEnumerable, "CID", "Cname", Model.CoreValuesID ))
Your HTTPOST :
[HTTPOST]
public ActionResult Create(CreateViewModel model)
{
//Now with your model you have the Id of CoreValue and SubjectType
//You could do
if (ModelState.IsValid)
{
QuestionRep.Add(model);
return RedirectToAction("Index");
}
return View(model);
}
Hope this can help you :)
Edit :
in my repository I do :
public void Add(Model.Models.LabExam.Examen entity)
{
using (var context = new PDSIDataContext())
{
var exam = BindModelExamenToRepExamen(entity);
context.Examen.InsertOnSubmit(exam);
context.SubmitChanges();
}
}
Binding methods (Repository.Examen represents my table, Repository is my project where I have a .dbml to represent my DB):
private static Repository.Examen BindModelExamenToRepExamen(Model.Models.LabExam.Examen modelExamen)
{
return new Repository.Examen
{
ID_Examen = modelExamen.ID,
ID_Examen_Type = modelExamen.ID_Examen_Type,
Date_Prescription = modelExamen.Date_Prescription,
Realise_Le = modelExamen.Realise_Le,
Statut = modelExamen.Statut,
Fait = modelExamen.Fait,
ID_Examen_Sous_Type = modelExamen.ID_Examen_Sous_Type,
ID_Examen_Sous_Sous_Type = modelExamen.ID_Examen_Sous_Sous_Type,
ID_Patient = modelExamen.ID_Patient,
Commentaires = modelExamen.Commentaires
};
}
I am quite confused with how to effectively use the Html.DropDownList helper for ASP.NET MVC.
Background: I have a 5-page form, which saves data to the form each time "Next" is clicked. Users may navigate back and forth between sections, so previous sections will already be pre-populated with previously-entered data.
This works for TextBoxes. But not DropDownLists. I have tried a load of different methods, including:
How to add static list of items in MVC Html.DropDownList()
Setting selected item to DropdownList in MVC Application?
I have a ViewModel such taht I have got my lists and my Model (a LINQ-to-SQL generated class) as properties. eg:
public class ConsultantRegistrationFormViewModel
{
public IConsultantRegistration ConsultantRegistration { get; private set; }
public SelectList Titles { get; private set; }
public SelectList Countries { get; private set; }
public SelectList Currencies { get; private set; }
public int CurrentSection { get; private set; }
private ConsultantRegistrationFormViewModel(IConsultantRegistration consultantRegistration)
{
ConsultantRegistration = consultantRegistration;
CurrentSection = 1;
Titles = new SelectList(new string[] { "Mr", "Mrs", "Miss", "Ms", "Dr", "Sir" });
Countries = new SelectList(countries.Select(q => q.Name));
Currencies = new SelectList(currencies,"CurrencyCode","FriendlyForm");
}
}
My Controller's Edit Action on GET looks like:
public class ConsultantRegistrationController : Controller
{
public IConsultantRegistrationRepository ConsultantRegistrationRepository { get; private set; }
public ICountryRepository CountryRepository { get; private set; }
public IEnumerable<ICountry> Countries { get; private set; }
public ConsultantRegistrationController()
{
ConsultantRegistrationRepository = RepositoryFactory.CreateConsultantRegistrationRepository();
CountryRepository = RepositoryFactory.CreateCountryRepository();
Countries = CountryRepository.GetCountries().ToArray();
}
public ActionResult Edit(Guid id, int sectionIndex)
{
IConsultantRegistration consultantRegistration = ConsultantRegistrationRepository.GetConsultantRegistration(id);
SelectList bankBranchCountriesSelectList = new SelectList(Countries, "BankBranchCountry", "CountryName", consultantRegistration.BankBranchCountry);
ViewData["bankBranchCountrySelectList"] = bankBranchCountriesSelectList;
return View(new ConsultantRegistrationFormViewModel(consultantRegistration,sectionIndex, Countries,Currencies));
}
}
With my View doing:
<%: Html.DropDownList("ConsultantRegistration.BankBranchCountry",ViewData["bankBranchCountrySelectList"] as SelectList) %>
This gives me the error:
DataBinding:
'IWW.ArrowPay.ConsultantRegistration.Data.Country'
does not contain a property with the
name 'BankBranchCountry'.
Which it does, have a look at the schema of this property:
public interface IConsultantRegistration
{
Guid ID { get; set; }
[DisplayName("Branch Country")]
string BankBranchCountry { get; set; }
}
(My LINQ-to-SQL type ConsultantRegistration implemented IConsultantRegistration)
It seems that it is trying to bind to the wrong type, though?
If I use this in my view (and use my Controller's Countries property):
<%: Html.DropDownList("ConsultantRegistration.BankBranchCountry ",Model.Countries,"(select a Country)") %>
I get the saved value fine, but my model doesn't update on POST.
And if I use this in my view:
<%: Html.DropDownListFor(model=>model.ConsultantRegistration.BankBranchCountry ",Model.Countries,"(select a Country)") %>
I get the list, and it POSTs the selected value back, but does not pre-select the currently selected item in my model on the view.
So I have a bit of the solution all over the place, but not all in one place.
Hope you can help fill in my ignorance.
Ok, I solved it. Proper hacky, but it gets the job done.
I'm using the ViewData in my view:
<%: Html.DropDownList("bankBranchCountrySelectList", ViewData["bankBranchCountrySelectList"] as SelectList)%>
With the following in my controller:
public ActionResult Edit(Guid id, int sectionIndex)
{
IConsultantRegistration consultantRegistration = ConsultantRegistrationRepository.GetConsultantRegistration(id);
ViewData["bankBranchCountrySelectList"] = Countries.Select(q => new SelectListItem() { Text = q.Name, Value = q.Name, Selected = (q.Name.Trim().Equals(consultantRegistration.BankBranchCountry, StringComparison.InvariantCultureIgnoreCase)) }); // bankBranchCountriesSelectList;
return View(new ConsultantRegistrationFormViewModel(consultantRegistration,sectionIndex, Countries,Currencies));
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, int sectionIndex, FormCollection formValues)
{
IConsultantRegistration consultantRegistration = ConsultantRegistrationRepository.GetConsultantRegistration(id);
UpdateModel(consultantRegistration);
ViewData["bankBranchCountrySelectList"] = Countries.Select(q => new SelectListItem() { Text = q.Name, Value = q.Name, Selected = (q.Name.Trim().Equals(consultantRegistration.BankBranchCountry, StringComparison.InvariantCultureIgnoreCase)) });
IEnumerable<RuleViolation> ruleViolations = consultantRegistration.GetRuleViolations(sectionIndex);
if (ruleViolations.Count() == 0)
{
// ...
}
else
{
ModelState.AddRuleViolations(ruleViolations);
return View(new ConsultantRegistrationFormViewModel(consultantRegistration, sectionIndex, Countries, Currencies));
}
}
Not ideal and breaks clean coding. No idea why it works, but that seems to be what MVC is all about with "convention over configuration".
This article was written with Multi-Select Lists in mind, but the principle applies equally to a single-selection drop down list:
http://www.stevefenton.co.uk/Content/Blog/Date/201002/Blog/How-To-Handle-Multiple-Select-Lists-In-ASP-NET-MVC/