How to create Static Dropdownlist values in MVC Model - asp.net-mvc

How can I prepare a model for Dropdownlist static values (not retrieved from database) like enum or list in MVC Model so that it could be used many times in a project? I would appreciate if you can give a good article? Thanks.

As always you could start with a view model:
public class MyViewModel
{
public string SelectedValue { get; set; }
public IEnumerable<SelectListItem> Values
{
get
{
return new[]
{
new SelectListItem { Value = "1", Text = "Item 1" },
new SelectListItem { Value = "2", Text = "Item 2" },
new SelectListItem { Value = "3", Text = "Item 3" },
};
}
}
}
then a controller:
public ActionResult Index()
{
var model = new MyViewModel();
return View(model);
}
and finally a view:
#model MyViewModel
#Html.DropDownListFor(x => x.SelectedValue, Model.Values)
For enums you could use some of the many posts out there illustrating custom helpers. Here's one blog post illustrating such helper: http://blogs.msdn.com/b/stuartleeks/archive/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums.aspx

Finally I have found the solution by describing the parameters as hidden input. I am not sure if there is a more elegant method in order to pass the parameters from View to Controller. Thank you so much for your good sample. I also marked as helpful all of your replies. Here is my final code for those who might encounter a similar problem:
ApplicantViewModel:
public class ApplicantViewModel
{
public IEnumerable<Applicant> Applicants { get; set; }
//Codes for Dropdownlist values
public string SelectedValue { get; set; }
public IEnumerable<SelectListItem> Values
{
get
{
return new[]
{
new SelectListItem { Value = "pdf", Text = "Pdf" },
new SelectListItem { Value = "excel", Text = "Excel" },
new SelectListItem { Value = "word", Text = "Word" }
};
}
}
}
ApplicantController:
public ViewResult Reporting()
{
var model = new ApplicantViewModel();
return View(model);
}
public ActionResult RenderReport(string SelectedValue, string name, string fileName, string dataSource, string table, string filter)
{
//Codes for rendering report
...
}
Reporting.cshtml:
#model MyProject.Models.ApplicantViewModel
#using (Html.BeginForm("RenderReport", "Applicant", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
<div>
#Html.DropDownListFor(model => model.SelectedValue, Model.Values, "-- select an option --")
<input type="hidden" name="name" value="Report1"/>
<input type="hidden" name="fileName" value="image rapor"/>
<input type="hidden" name="dataSource" value="ApplicantDataset"/>
<input type="hidden" name="table" value="ApplicantsView"/>
<input type="hidden" name="filter" value="David"/>
<input type="submit" value="submit" />
</div>
}

Related

dropdownlist in MVC from database

I am trying to pull the data from a table stored in SQL 2008 into my MVC4
In My Controller :
public ActionResult Test()
{
SurveyEntities survey = new SurveyEntities();
var doctorList = survey.Doctors.ToList();
return View(doctorList);
}
and in my View:
#model IEnumerable<Survey.DataAccess.Doctor>
#{
ViewBag.Title = "Test";
}
<h2>Test</h2>
#using (Html.BeginForm("Test", "Home", FormMethod.Post))
{
#Html.DropDownListFor(m => m.)
}
But I am not able to access the field name in m, say for eg., the doctor's name, to bind it to the dropdownlist.
Where am i going wrong ?
If you dont need to bind to the result value you can also use Html.DropDownList('name', new SelectList(Model)) If you have to use DropDownListFor you would have to change your model and add a property to bind the select result like Html.DropDownListFor(m=>m.DoctorId, new SelectList(Model.Doctors).....
Normally, you want to use ViewModel, so that you can retrieve the selected doctorId when the form is posted back to server.
For example,
Model
public class SurveyModel
{
public string SelectedDoctorId { get; set; }
public IList<SelectListItem> AvailableDoctors { get; set; }
public SurveyModel()
{
AvailableDoctors = new List<SelectListItem>();
}
}
View
#model DemoMvc.Models.SurveyModel
#using (Html.BeginForm("Index", "Home"))
{
#Html.DropDownListFor(m => m.SelectedDoctorId, Model.AvailableDoctors)
<input type="submit" value="Submit" />
}
Controller
public ActionResult Index()
{
var model = new SurveyModel
{
AvailableDoctors = GetDoctorListItems()
};
return View(model);
}
[HttpPost]
public ActionResult Index(SurveyModel model)
{
if (ModelState.IsValid)
{
var doctorId = model.SelectedDoctorId;
// Do something
return View("Success");
}
// If we got this far, something failed, redisplay form
// Fill AvailableDoctors again; otherwise, DropDownList will be blank.
model.AvailableDoctors = GetDoctorListItems();
return View(model);
}
private IList<SelectListItem> GetDoctorListItems()
{
/*
SurveyEntities survey = new SurveyEntities();
return survey.Doctors
.Select(d => new SelectListItem {Text = d, Value = d.ToString()})
.ToList();
*/
// Simulate doctors return from database.
return new List<SelectListItem>
{
new SelectListItem {Text = "John Doe", Value = "1"},
new SelectListItem {Text = "Eric Newton", Value = "2"}
};
}
you can put this code in the Test method:
> ViewData["doctors"] = new SelectList(doctorList,"value", "text");
and then in a view:
#using (Html.BeginForm("Test", "Home", FormMethod.Post))
{
#Html.DropDownList("name", ViewData["doctors"] as SelectList)
input type="submit" value="Submit" />
}

Passing Model data from View to Controller

I am trying to pass the Model data from a View (and PartialView within the View) back to the Controller upon HttpPost. (Adapted from Pass SelectedValue of DropDownList in Html.BeginForm() in ASP.NEt MVC 3)
Why? I want to show a list of assets each with a DropDownList and number of options. Upon submission of form to read the selected items from DropDownList.
My 2 (simplified) models:
public class Booking
{
public int BookingID { get; set; }
public int StoreID { get; set; }
...
public IEnumerable<AssetShort> Assets { get; set; }
}
and
public class AssetShort
{
public int AssetID { get; set; }
....
public int SelectedAction { get; set; }
public IEnumerable<SelectListItem> ActionList { get; set; }
}
In my Booking Controller > Create I build the List:
public ActionResult Booking(int id)
{
// get myBag which contains a List<Asset>
// booking corresponds to 'id'
var myAssets = new List<AssetShort>();
foreach (var a in myBag.Assets)
{
var b = new AssetShort();
b.AssetID = a.ID;
b.SelectedAction = 0;
b.ActionList = new[]
{
new SelectListItem { Selected = true, Value = "0", Text = "Select..."},
new SelectListItem { Selected = false, Value = "1", Text = "Add"},
new SelectListItem { Selected = false, Value = "2", Text = "Remove"},
new SelectListItem { Selected = false, Value = "3", Text = "Relocate"},
new SelectListItem { Selected = false, Value = "4", Text = "Upgrade"},
new SelectListItem { Selected = false, Value = "5", Text = "Downgrade"}
};
myAssets.Add(b);
};
var model = new BookingRequirementsViewModel
{
BookingID = booking.ID,
StoreID = booking.StoreID,
Assets = myAssets.ToList(),
};
return View(model);
My View:
#model uatlab.ViewModels.BookingRequirementsViewModel
#{
ViewBag.Title = "Booking step 2";
}
<h4>Your booking ref. #Model.BookingID</h4>
#using (Html.BeginForm("Booking2", "Booking", FormMethod.Post))
{
<fieldset>
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.StoreID)
#Html.Partial("_Assets", Model.StoreAssets)
<input type="submit" value="Cancel" class="btn btn-default" />
<input type="submit" value="Next" class="btn btn-default" />
</fieldset>
}
The Partial View includes
#foreach (var item in Model)
{
<tr>
<td>#item.Name</td>
<td>#item.Number</td>
<td>#Html.DropDownListFor(modelItem=>item.SelectedAction, item.ActionList)</td>
</tr>
}
So, all this works fine in the browser and I can select dropdowns for each asset listed but when I submit the only value posted back is the StoreID as it is in a "HiddenFor".
The booking2 controller has the model for a parameter:
public ActionResult Booking2(BookingRequirementsViewModel model)
{
//loop through model.Assets and display SelectedActions
}
Let me make it clear what the problems is - in Booking2 controller the Model is null when viewed in Debug mode and I get error "Object reference not set to an instance of an object."
Any ideas please how to pass back the Model to controller from view?
Regards
Craig
You need to create an EditorTemplate for AssetShort. I also suggest moving ActionList to the BookingRequirementsViewModel so your not regenerating a new SelectList for each AssetShort
The models you have posted aren't making sense. Your controller has var model = new BookingRequirementsViewModel { ..., Assets = myAssets.ToList() }; but in the view you refer to #Html.Partial("_Assets", Model.StoreAssets)? Are these 2 different properties. I will assume that StoreAssets is IEnumerable<AssetShort>
/Views/Shared/EditorTemplates/AssetShort.cshtml
#model AssetShort
<tr>
<td>#Html.DispayFor(m => m.Name)</td>
....
<td>
#Html.DropDownListFor(m => m.SelectedAction, (IEnumerable<SelectListItem>)ViewData["actionList"], "--Please select--")
#Html.ValidationMessageFor(m => m.SelectedAction)
</td>
</tr>
In the main view
#model uatlab.ViewModels.BookingRequirementsViewModel
....
#using (Html.BeginForm()) // Not sure why you post to a method with a different name
{
....
#Html.HiddenFor(m => m.StoreID)
#Html.EditorFor(m => m.StoreAssets, new { actionList = Model.ActionList })
....
}
In the controller
public ActionResult Booking(int id)
{
....
var model = new BookingRequirementsViewModel
{
BookingID = booking.ID,
StoreID = booking.StoreID,
Assets = myBag.Assets.Select(a => new AssetShort()
{
AssetID = a.ID,
SelectedAction = a.SelectedAction, // assign this if you want a selected option, otherwise the "--Please select--" option will be selected
....
})
};
ConfigureViewModel(model); // Assign select list
return View(model);
}
And a separate method to generate the SelectList because it needs to be called in the GET method and again in the POST method if you return the view. Note use the overload of DropDownListFor() to generate the option label (null value) as above, and there is no point setting the Selected property (the value of SelectedAction determines what is selected, not this)
private ConfigureViewModel(BookingRequirementsViewModel model)
{
model.ActionList = new[]
{
new SelectListItem { Value = "1", Text = "Add"},
....
new SelectListItem { Value = "5", Text = "Downgrade"}
};
}
and the POST
public ActionResult Booking(BookingRequirementsViewModel model)
{
if (!ModelState.IsValid)
{
ConfigureViewModel(model); // Re-assign select list
return View(model);
}
// save and redirect
}
I recommend also making SelectedAction nullable with the [Required] attribute so you get client and server side validation
public class AssetShort
{
public int AssetID { get; set; }
....
[Required]
public int? SelectedAction { get; set; }
}

MVC Radio Button Lists are not grouped when using the HtmlHelper class

Having trouble creating a list of radio buttons that are grouped together, in MVC 3 specifically, but this also applies to MVC 2.
The problem arises when radio buttons are generated using Html helpers and the model is part of an array.
Here is the cut down version of my code.
public class CollectionOfStuff {
public MVCModel[] Things { get; set }
}
/*This model is larger and represents a Person*/
public class MVCModel {
[UIHint("Hidden")]
public string Id { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
/*Assigned to new CollectionOfStuff property Things*/
var items = new[] {
new MVCModel() { Id="0" Name = "Name here" }, new MVCModel() { Id="1" Name = "Name there" }
}
My parent view
#model CollectionOfStuff
#for (int i = 0; i < Model.Things.Length; i++) {
#Html.EditorFor(m => m.Things[i]);
}
My view rendering individual MVCModel objects
#Model MVCModel
#{
var attr = new {
Checked = Model.IsSelected ? "checked=checked" : ""
};
}
#Html.RadioButtonFor(model => model, Model.Id, attr)
Produces this output:
<input type="radio" value="0" name="MVCModel[0]" id="MVCModel_0_" data-val-required="You need to choose" data-val="true" />
<input type="radio" value="1" name="MVCModel[1]" id="MVCModel_1_" data-val-required="You need to choose" data-val="true" />
The radio buttons are not grouped, however it has the obvious advantage of writing out the meta data for validation.
The other way is by calling:
#Html.RadioButton(name: "GroupName", value: Model.Id, isChecked: Model.IsSelected)
Produces:
<input type="radio" value="0" name="MVCModel[0].GroupName" id="MVCModel_0__GroupName">
<input type="radio" value="1" name="MVCModel[1].GroupName" id="MVCModel_1__GroupName">
Again, this doesn't produce the desired result. It's also missing the validation meta data.
Another other option is creating a custom template, but the problem with this approach is that all the meta data required for validation is not present.
Any ideas on how I can create grouped radio buttons or obtain meta data so I can create a template myself?
You haven't shown how does your view model look like but you could group them by some property. So let's take an example:
public class MyViewModel
{
[Required]
public string SomeProperty { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
View:
#model AppName.Models.MyViewModel
#using (Html.BeginForm())
{
<div>A: #Html.RadioButtonFor(x => x.SomeProperty, "a")</div>
<div>B: #Html.RadioButtonFor(x => x.SomeProperty, "b")</div>
#Html.ValidationMessageFor(x => x.SomeProperty)
<input type="submit" value="OK" />
}
Now if you want to preselect some radio simply set the property of the view model to the corresponding value of the radio instead of writing some ugly C# code in your views:
public ActionResult Index()
{
var model = new MyViewModel
{
SomeProperty = "a" // select the first radio
};
return View(model);
}
Obviously this technique works with any simple property type (not only strings) and with any number of radio buttons that could be associated to this property.

primary keys in form for post-back?

I have an asp.NET mvc 3 with razor website. I have a web page that is displaying a list of data from a database in a form such as:
<input type="text" name="blah1" value="blah" />
<input type="text" name="blah2" value="blahblah" />
<input type="text" name="blah3" value="blahblah" />
Each row above is assoicated with a primary key. When the user hits submit and posts back the FormCollection to the controller.. how do I go about getting the primary keys of each blah? Do I add a hidden field for each row that contains the primary key of that row? If so, how do I know which blah it is associated with as the FormCollection is just a dictionary?
I would recommend you using a view model:
public class MyViewModel
{
public string Id { get; set; }
public string Text { get; set; }
}
and then in your controller action you would send a list of those models to the view:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new[]
{
new MyViewModel { Id = "1", Text = "blah" },
new MyViewModel { Id = "2", Text = "blahblah" },
new MyViewModel { Id = "3", Text = "blahblah" },
};
return View(model);
}
[HttpPost]
public ActionResult Index(IEnumerable<MyViewModel> model)
{
// Here you will get a collection of id and text for each item
...
}
}
and the view you could use hidden fields for the id and a textbox for the value:
#model IEnumerable<MyViewModel>
#using (Html.BeginForm())
{
#Html.EditorForModel()
<input type="submit" value="OK" />
}
and the corresponding editor template (~/Views/Shared/EditorTemplates/MyViewModel.cshtml):
#model MyViewModel
#Html.HiddenFor(x => x.Id)
#Html.TextBoxFor(x => x.Text)

How does Model binding with a selectlist work?

I'm having problems retrieving the values of a selectlist in my form collection. I've tried making a viewmodel with an attribute with the same name as the select list.
I'm honestly just realizing I REALLY don't understand how model binding works with selectlists. I've just been assuming that the following conventions apply:
Name the select list the same thing as the attribute on the model you want it to bind to.
Apart from that, I really don't get it. I've looked at several books on it and they're useless frankly.
How does a select list work with a) form collection and b) a particular model?
Here's an example:
Model:
public class MyViewModel
{
public string SelectedItemValue { get; set; }
public IEnumerable<SelectListItem> Items { get; set; }
}
Controller:
public class HomeController: Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
// TODO: Fetch those from a repository
Items = new SelectList(
new[]
{
new SelectListItem { Value = "1", Text = "Item 1" },
new SelectListItem { Value = "2", Text = "Item 2" },
new SelectListItem { Value = "3", Text = "Item 3" },
},
"Value",
"Text"
)
};
}
[HttpPost]
public ActionResult Index(string selectedItemValue)
{
// Here you get the selected value from the dropdown
return ...
}
}
View:
<% using (Html.BeginForm()) { %>
<%= Html.DropDownListFor(x => x.SelectedItemValue, Model.Items)
<input type="submit" value="OK" />
<% } %>

Resources