How to create drop down list in mvc - model-view-controller

This is my controller
[AllowAnonymous]
public ActionResult Register()
{
ViewBag.Name = new SelectList(context.Roles.ToList(), "Name", "Name");
return View();
}
This is my Create view part
<div class="form-group">
#Html.Label("Select Your User Type", new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#*#Html.DropDownList("Name")*#
#Html.DropDownList("Name",(SelectList)ViewBag.Name )
</div>
</div>
i can load the form with drop down. but when I am try to save the record it gives an error "The ViewData item that has the key 'Name' is of type 'System.String' but must be of type 'IEnumerable'."

Do this:
[AllowAnonymous]
public ActionResult Register()
{
var items = new List<SelectListItem>();
foreach (var role in context.Roles)
{
items.Add(new SelectListItem {Text = role.Name, Value = role.Value});
}
var result = new SelectList(items);
ViewBag.Name = result;
return View();
}
View
#Html.DropDownList("Name",ViewBag.Name)
But can I suggest that you avoid ViewBag and use strongly typed models.
Look here

Related

how can i get dropdownlist id in controller when we select an item using mvc4

I have dropdownlst which i have filled from database. Now i need to get the selected value in Controller do some manipulation. But null data will get. Code which i have tried.
##View##
#using (Html.BeginForm()) {
#Html.DropDownList("SupplierId", ViewBag.PurSupName as SelectList, new {#class = "form-control",style = "width: 200px;",id="supId"})
}
## Controller ##
public ActionResult ItemPurchased()
{
POS_DBEntities2 db = new POS_DBEntities2();
var query = from i in db.TBL_Account
where i.Type == "supplier"
select i;
ViewBag.PurSupName = new SelectList(query, "AccountId", "AccountName");
return PartialView("ItemPurchased", new List<PurchasedItem>());
}
##Controller##
public ActionResult GetPurchasedItem()
{
var optionsValue = this.Request.Form.Get("SupplierId");
return View();
}
You can try with below changes.
#using (Html.BeginForm("GetPurchasedItem","YourController")) {
#Html.DropDownList("SupplierId", ViewBag.PurSupName as SelectList, new {#class = "form-control",style = "width: 200px;",id="supId"})
<input type="submit" value="OK" />
}
Controller will be
[HttpPost]
public ActionResult GetPurchasedItem(string SupplierId)
{
var optionsValue = SupplierId;
//..............
return View();
}
It should work normally..

MVC3 passing incorrectly formatted datetime to Controller but correcting it in the Controller action gives ModelState error

Am I the only one having this problem or I am doing it in totally wrong direction.
I have a View passing DateTime value:
<div class="control-group">
#Html.Label("Appointment date", null, new { #class = "control-label" })
<div class="controls">
<div class="input-append">
#Html.TextBoxFor(model => model.Appointment.Client_PreferredDate, new { #readonly = "readonly" })
<span class="add-on margin-fix"><i class="icon-th"></i></span>
</div>
<p class="help-block">
#Html.ValidationMessageFor(model => model.Appointment.Client_PreferredDate)
</p>
</div>
The values are passed into the Controller action ( I can see the value, and I know it is giving the format that is not DateTime, i.e. it is going to be in dd-MM-yyyy). Then in the Controller I will reformat it.
[HttpPost]
public ActionResult RequestAppointment(General_Enquiry model, FormCollection fc)
{
model.Appointment.Client_PreferredDate = Utilities.formatDate(fc["Appointment.Client_PreferredDate"]);
ModelState.Remove("Appointment.Client_PreferredDate");
try
{
if (ModelState.IsValid)
{
model.Branch_Id = Convert.ToInt32(fc["selectedBranch"]);
model.Appointment.Branch_Id = Convert.ToInt32(fc["selectedBranch"]);
db.General_Enquiry.AddObject(model);
db.SaveChanges();
return RedirectToAction("AppointmentSuccess", "Client");
}
}
catch (Exception e)
{
Debug.WriteLine("{0} First exception caught.", e);
Debug.WriteLine(e.InnerException);
ModelState.AddModelError("", e);
}
return View(model);
}
The best I can do is to use ModelState.Remove(), which I feel really uncomfortable with. I suspect that when my Model is passed from the View to Controller, the ModelState is already set to Invalid before I can do anything in the Controller. Any ideas?
If I call the ModelState.Remove() everything went smoothly, the DateTime is accepted by SQL server database.
If at least I can update or 'refresh' ModelState at any point it'll fix my problem.
Cheers.
I'd recommend you using a view model and a custom model binder for the DateTime formats.
We start by defining this view model:
public class MyViewModel
{
[DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
public DateTime PreferredDate { get; set; }
}
then a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
PreferredDate = DateTime.Now.AddDays(2)
};
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// model.PreferredDate will be correctly bound here so
// that you don't need to twiddle with any FormCollection and
// removing stuff from ModelState, etc...
return View(model);
}
}
a View:
#model MyViewModel
#using (Html.BeginForm())
{
#Html.LabelFor(x => x.PreferredDate)
#Html.EditorFor(x => x.PreferredDate)
#Html.ValidationMessageFor(x => x.PreferredDate)
<button type="submit">OK</button>
}
and finally a custom model binder to use the specified format:
public class MyDateTimeModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var displayFormat = bindingContext.ModelMetadata.DisplayFormatString;
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (!string.IsNullOrEmpty(displayFormat) && value != null)
{
DateTime date;
displayFormat = displayFormat.Replace("{0:", string.Empty).Replace("}", string.Empty);
// use the format specified in the DisplayFormat attribute to parse the date
if (DateTime.TryParseExact(value.AttemptedValue, displayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
{
return date;
}
else
{
bindingContext.ModelState.AddModelError(
bindingContext.ModelName,
string.Format("{0} is an invalid date format", value.AttemptedValue)
);
}
}
return base.BindModel(controllerContext, bindingContext);
}
}
that will be registered in Application_Start:
ModelBinders.Binders.Add(typeof(DateTime), new MyDateTimeModelBinder());

View "ChangePassword" in MVC 3

Can you help me to build my "ChangePassword" View in MVC3 ?
Here what I have tried to do:
ProfileTeacherController.cs
public ViewResult ChangePassword(int id)
{
var user = User.Identity.Name;
int inter = int.Parse(user);
var teachers = from t in db.Teachers
where t.AffiliationNumber == inter
select t;
Teacher teacher = new Teacher();
foreach (var teach in teachers)
{
teacher = teach;
}
return View(teacher);
}
[HttpPost]
public ActionResult ChangePassword(Teacher teacher)
{
if (ModelState.IsValid)
{
// How can I compare the two fields password in my view ?
db.Entry(teacher).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Edit", "ProfileTeacher", new { id = teacher.TennisClubID });
}
return View(teacher);
}
Here the ChangePassword (View)
#model TennisOnline.Models.Teacher
#{
ViewBag.Title = "ChangePassword";
}
<h2>Changement du mot de passe</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend></legend>
<div class="editor-label">
#Html.Label("Enter the new password")
</div>
<div class="editor-field">
#Html.PasswordFor(model => model.Pin, new { value = Model.Pin })
</div>
<div class="editor-label">
#Html.Label("Confirm your password")
</div>
<div class="editor-field">
#Html.Password("ConfirmPassword")
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
So, How can I verify in my controller if the two passwords are the same, please ? Thanks in advance
In addition you can add the message to be shouwn when the two password are not the same in the Compare attribute.
[Compare("NewPassword", ErrorMessage = "The new password and confirm password do not match.")]
I would recommend the usage of a view model:
public class TeacherViewModel
{
...
[Compare("ConfirmPassword")]
public string Password { get; set; }
public string ConfirmPassword { get; set; }
}
now have your view take the view model and also your Post action.
In addition to that in your GET action you seem to have written some foreach loop which I don't see its usage. You could simplify:
[Authorize]
public ViewResult ChangePassword(int id)
{
var user = User.Identity.Name;
int inter = int.Parse(user);
var teacher = db.Teachers.SingleOrDefault(t => t.AffiliationNumber == inter);
return View(teacher);
}

Error when trying to post MVC form with Dropdown list in it

I looked at similar posts but nothing working for my case.
I have a form which loads fine and I see the categories dropdown with all categories in it.
The problem is when I try to post the form.
I get this error:
The ViewData item that has the key 'Category' is of type 'System.String' but must be of type 'IEnumerable'.
#Html.DropDownList("Category", Model.Categories) <-- red color
Here is my view:
#using (Html.BeginForm("Save", "Album", FormMethod.Post, new { id = "frmNewAlbum" }))
{
#Html.DropDownList("Category", Model.Categories)
}
Here is my model:
public class AlbumModel
{
public string Title { get; set; }
public string Category { get; set; }
public List<SelectListItem> Categories { get; set; } <-- holds categories
}
This is the controller actions to view the page:
[HttpGet]
public ActionResult Save()
{
var model = new AlbumModel();
var categories = new List<SelectListItem>() { new SelectListItem() { Text = "-- pick --" } };
categories.AddRange(svc.GetAll().Select(x => new SelectListItem() { Text = x.Name, Value = x.Name }));
model.Categories = categories;
return View(model);
}
Action that receives the post:
[HttpPost]
public ActionResult Save(AlbumModel model)
{
var album = new AlbumDoc()
{
Category = model.Category,
Title = model.Title,
};
svc.SaveAlbum(album);
return View(model);
}
In your POST action you seem to be redisplaying the same view but you are not populating the Categories property on your view model which will contain the dropdown list values. And by the way I would recommend you using strongly typed helper. So:
public class AlbumController: Controller
{
[HttpGet]
public ActionResult Save()
{
var model = new AlbumModel();
model.Categories = GetCategories();
return View(model);
}
[HttpPost]
public ActionResult Save(AlbumModel model)
{
var album = new AlbumDoc()
{
Category = model.Category,
Title = model.Title,
};
svc.SaveAlbum(album);
model.Categories = GetCategories();
return View(model);
}
private IList<SelectListItem> GetCategories()
{
return svc
.GetAll()
.ToList()
.Select(x => new SelectListItem
{
Text = x.Name,
Value = x.Name
});
}
}
and in your view:
#model AlbumModel
...
#using (Html.BeginForm("Save", "Album", FormMethod.Post, new { id = "frmNewAlbum" }))
{
#Html.DropDownListFor(
x => x.Category,
Model.Categories,
-- pick --
)
}

DropdownListFor default value

Is there a simple way to add a "--Please select--" default option to a DropDownListFor in MVC 3?
So, I did something like this:
#Html.DropDownListFor(model => model.Dessert,
new SelectList(Model.AvailableDesserts, "DessertID", "DessertName"),
"---Select A Dessert ---")
Seems to work pretty well. Dessert in my viewmodel is the one selected by the user. AvailableDesserts is a collection of ones to pick from.
I have a couple extension methods on SelectList
public static SelectList PreAppend(this SelectList list, string dataTextField, string selectedValue, bool selected=false)
{
var items = new List<SelectListItem>();
items.Add(new SelectListItem() { Selected = selected, Text = dataTextField, Value = selectedValue });
items.AddRange(list.Items.Cast<SelectListItem>().ToList());
return new SelectList(items, "Value", "Text");
}
public static SelectList Append(this SelectList list, string dataTextField, string selectedValue, bool selected=false)
{
var items = list.Items.Cast<SelectListItem>().ToList();
items.Add(new SelectListItem() { Selected = selected, Text = dataTextField, Value = selectedValue });
return new SelectList(items, "Value", "Text");
}
public static SelectList Default(this SelectList list,string DataTextField,string SelectedValue)
{
return list.PreAppend(DataTextField, SelectedValue, true);
}
Then my razor looks like:
#Html.DropDownListFor(m=>m.SelectedState,
Model.StateList().Default("Select One",""))
Hi what about trying this (in case you use DisplayFor method)
private IEnumerable<SelectListItem> AddDefaultOption(IEnumerable<SelectListItem> list, string dataTextField, string selectedValue)
{
var items = new List<SelectListItem>();
items.Add(new SelectListItem() { Text = dataTextField, Value = selectedValue});
items.AddRange(list);
return items;
}
Then just add this code to your Controller
//lambda expression binding
ViewBag.YourList = db.YourTable.Select(x => x).ToList().Select(x => new SelectListItem
{
Value = x.Id.ToString(),
Text = x.DisplayName.ToString()
});
ViewBag.YourList = AddDefaultOption(ViewBag.YourList, "Select One...", "null", true);
And finally at the View you could display a dropdown, combobox just like this
<div class="editor-label">
Your Label
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.ForeignKey, (IEnumerable<SelectListItem>)ViewBag.YourList)
</div>
I wanted to set the default value to whatever was passed in as a Url Parameter called SiteType:
<div class="form-group">
#Html.LabelFor(model => model.Type, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.Type, ChangeOrderSite.SiteTypeNames.Select(s => new SelectListItem { Text = s.Value, Value = s.Key.ToString(), Selected = s.Key.ToString() == Request["SiteType"] }), new { #class = "control-label col-md-2" })
#Html.ValidationMessageFor(model => model.Type)
</div>
</div>
My drop down is a list of Site Types.
I like the following method:
#Html.DropDownListFor(m => m.SelectedId, new SelectList(Model.Items, "Id", "Name"), new SelectListItem() { Text = "None", Value = "", Selected = true }.Text, new { #class = "form-control search-select-input btn btn-block btn-outline-secondary dropdown-toggle p-1" })
Where Items is an IEnumerable of type you want to display in the dropdown. And you can change out whatever bootstrap classes you want in the last parameter.
This way allows you to set a default label and specify the value of the label if needed.

Resources