Unable to bind ViewData to a dropdown list - c#

I am working on an asp.net mvc 4 application where I am trying to add delete a user functionality for an admin where I should be able to select a user from dropdown list and delete him.
private static IEnumerable<SelectListItem> getUsers()
{
WhiteBoardAppContext db = new WhiteBoardAppContext();
IEnumerable<SelectListItem> numbers = (from i in db.UserProfiles
select new SelectListItem
{ Text= i.UserName,
Value=i.UserId.ToString()
});
return numbers.ToList();
}
[Authorize(Roles = "Admin")]
public ActionResult DeleteUser()
{
var list = (IEnumerable<SelectListItem>)ViewData["UserList"];
list = getUsers();
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Admin")]
public ActionResult DeleteUser(UserProfile model)
{
if (ModelState.IsValid)
{
try
{
if (model.UserName == null)
{
TempData["ErrorMessage"] = "Username required.";
return RedirectToAction("Register", "Account");
}
else
{
var user = Membership.GetUser(model.UserName);
if (user == null)
{
TempData["ErrorMessage"] = "User Does Not exist.";
return RedirectToAction("Register", "Account");
}
else
{
Membership.DeleteUser(model.UserName);
}
return RedirectToAction("Register", "Account");
}
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
DeleteUser.cshtml
#model WhiteBoardApp.Models.UserProfile
#using (Html.BeginForm("DeleteUser", "Account"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<fieldset>
<div class="container-fluid">
<ol>
<li>
#Html.LabelFor(m => m.UserName)
#Html.DropDownList("UserList", (IEnumerable<SelectListItem>)ViewData["UserList"])
<span style="color:red;">#TempData["ErrorMessage"]</span>
</li>
</ol>
<input type="submit" value="Delete User" />
</div>
</fieldset>
}
But, the above code threw me There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'UserList'.
May I know where I was wrong?

You need to add your users to the ViewData dictionary:
[Authorize(Roles = "Admin")]
public ActionResult DeleteUser()
{
ViewData["UserList"] = getUsers();
return View();
}
Also your usage of DropDownList helper is wrong since the first parameter should be a name of input that is going to contain selected user and not a select list itself.
in your case var list = (IEnumerable<SelectListItem>)ViewData["UserList"]; will return null so there is no actual assignment.
But in general I would advise you not to use ViewData but create a VieModel and put all the required data there:
public class DeleteUserViewModel
{
public IList<SelectListItem> UserList {get;set;}
public int SelectedUserId {get;set;}
}
Controller :
[Authorize(Roles = "Admin")]
[HttpGet]
public ActionResult DeleteUser()
{
var model = new DeleteUserViewModel{
UserList = getUsers()
};
return View(model);
}
[HttpPost]
public ActionResult DeleteUser(DeleteUserViewModel model)
{
int userToDelete = model.SelectedUserId;
//delete user logic here
}
View:
#model WhiteBoardApp.Models.DeleteUserViewModel
#using (Html.BeginForm("DeleteUser", "Account"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<fieldset>
<div class="container-fluid">
<ol>
<li>
#Html.LabelFor(m => m.UserName)
#Html.DropDownListFor(m=>m.SelectedUserId, Model.UserList )
<span style="color:red;">#TempData["ErrorMessage"]</span>
</li>
</ol>
<input type="submit" value="Delete User" />
</div>
</fieldset>
}

Related

Error in related DropDownList's when page refreshes

I have two related ddl's. When page loads, I can POST them to controller and everything is ok. But also I have some fields in page, and if they are empy I call ModalError in my controller, then page should be reloaded with text of errors. But it throughs an error, that says IEnumerable<SelectList> with name City is empty. What is the problem?
View:
#using (#Html.BeginForm())
{
<div>
#Html.LabelFor(model=>model.Buyer.buyers_name)
</div>
<div>
#Html.EditorFor(model=>model.Buyer.buyers_name)
#Html.ValidationMessageFor(model=>model.Buyer.buyers_name)
</div>
<div>
#Html.LabelFor(model=>model.Buyer.buyers_email)
</div>
<div>
#Html.EditorFor(model=>model.Buyer.buyers_email)
#Html.ValidationMessageFor(model=>model.Buyer.buyers_email)
</div>
<div>
#Html.LabelFor(model=>model.Buyer.buyers_phone)
</div>
<div>
#Html.EditorFor(model=>model.Buyer.buyers_phone)
#Html.ValidationMessageFor(model=>model.Buyer.buyers_phone)
</div>
<div>
<h2>Выберите адрес доставки:</h2>
<h3>Выберите город</h3>
#Html.DropDownList("City", ViewBag.cities as SelectList, new { id = "city" })
<h3>Выберите адрес</h3>
#Html.DropDownList("Address", ViewBag.addresses as SelectList, new { id = "address" })
</div>
<input type="submit" value="Send" class="btn" />
}
Controller:
public ActionResult GetItems(decimal id)
{
return PartialView(_db.bs_delivery_type.Where(x => x.delivery_city_id == id).ToList());
}
public ActionResult Checkout()
{
int selectedIndex = 1;
SelectList cities = new SelectList(_db.bs_cities, "cities_id", "cities_name", selectedIndex);
ViewBag.cities = cities;
SelectList addresses = new SelectList(_db.bs_delivery_type.Where(x => x.delivery_city_id == selectedIndex), "delivery_id", "delivery_address");
ViewBag.addresses = addresses;
return View();
}
[HttpPost]
public ActionResult Checkout(Cart cart, DeliveryModel deliveryModel, decimal city, decimal address)
{
if (cart.Lines.Count() == 0)
{
ModelState.AddModelError("", "Your cart is empty");
}
if (ModelState.IsValid)
{
//adds to db;
return View("Completed");
}
else
{
return View(deliveryModel);
}
}
DeliveryModel:
public class DeliveryModel
{
public bs_buyers Buyer { get; set; }
public List<bs_cities> CitiesModel { get; set; }
public SelectList FilteredDelivery { get; set; }
}
Also PartialView GetItems:
<select id="address" name="Address">
#foreach (var item in Model)
{
<option value="#item.delivery_id">#item.delivery_address</option>
}
As you invoke the Checkout Action in your Controller via HttpPost you then return the Checkout View in case the ModelState is invalid. However you do net set your ViewBag Variables as you do in your HttpGet Action.
You have to set ViewBag Variables in each and every Action. In this case I would recommend a separate method that gets invoked in both Actions.
private void SetViewBagForCheckout(){
int selectedIndex = 1;
SelectList cities = new SelectList(_db.bs_cities, "cities_id", "cities_name", selectedIndex);
ViewBag.cities = cities;
SelectList addresses = new SelectList(_db.bs_delivery_type.Where(x => x.delivery_city_id == selectedIndex), "delivery_id", "delivery_address");
ViewBag.addresses = addresses;
}

The model item passed into the dictionary is of type List`1 but this dictionary requires a model item of type IEnumerable

thanks in advance for helping.
New to MVC so is probably easy to answer. I'm getting this error and have no idea what any of it means. This is my code:
My view:
#model carBayWebsite.Models.WishList
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm("Create",
"WishLists",
FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Add to WishList?</h4>
<hr />
<p>Are you sure you want to add this to your Wish List?</p>
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.HiddenFor(m => m.AdvertId)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.HiddenFor(m => m.AdvertId)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Add" class="btn btn-default"/>
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
My Controller
public class WishListsController : Controller
{
private Entities2 db = new Entities2();
public ActionResult Index()
{
string userName = User.Identity.GetUserName();
var wishlist = from ads in db.Adverts
join wish in db.WishLists
on ads.AdvertId equals wish.AdvertId
where wish.UserId.Contains(userName)
select wish;
return View(wishlist.ToList());
}
// GET: WishLists/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
WishList wishList = db.WishLists.Find(id);
if (wishList == null)
{
return HttpNotFound();
}
return View(wishList);
}
public ActionResult Create(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
else
{
string usID = User.Identity.GetUserId().ToString();
int adID = Convert.ToInt32(id);
WishList wishList = db.WishLists.Find(id);
ViewBag.userId = usID;
ViewBag.advertId = adID;
return View(wishList);
}
}
// POST: WishLists/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(WishList wishList)
{
if (ModelState.IsValid)
{
db.WishLists.Add(new WishList
{
UserId = ViewBag.userId,
AdvertId = Convert.ToInt32(ViewBag.advertID),
});
try {
db.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
Trace.TraceInformation("Property: {0} Error: {1}",
validationError.PropertyName,
validationError.ErrorMessage);
}
}
}
return RedirectToAction("Index");
}
return View(wishList);
}
Could anyone figure out what's gone wrong? From looking around, I feel like its something really simple like the first like of the View but I can't pin it down! :)
Error details
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[carBayWebsite.Models.Advert]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[carBayWebsite.Models.WishList]'
The view you showed us is Create I think.(Because header is 'Create')
You are passing to Create view whishList which is type of WhisList return View(wishList);
But your view waits for Advert at the start of your view: #model carBayWebsite.Models.Advert
I think this is the problem. Let me know if it isn't.

Login and register on the same page ASP.NET MVC

I want to have both login forms and register forms on the same page.
I have the following code:
#model MusicRank.Models.AuthenticationModel
#{
ViewBag.Title = "Log In";
}
<h2>Log In</h2>
#Html.ValidationSummary(true)
#using (#Html.BeginForm("LogIn", "Auth", FormMethod.Post))
{
#Html.EditorFor(model => model.LoginModel.Email)
#Html.EditorFor(model => model.LoginModel.Password)
<p>
<button type="submit">Log In</button>
</p>
}
<h2>Register</h2>
#Html.ValidationSummary(false)
#using (Html.BeginForm("Register", "Auth", FormMethod.Post))
{
#Html.EditorFor(model => model.RegisterModel.Email)
#Html.EditorFor(model => model.RegisterModel.Password)
#Html.EditorFor(model => model.RegisterModel.Country)
<p>
<button type="submit">Register</button>
</p>
}
As u can see, I have to models to work with here. AuthenticationModel looks like this:
public class AuthenticationModel
{
public LogInModel LoginModel { get; set; }
public RegisterModel RegisterModel { get; set; }
}
When I try to register and hit submit, the values that are passed to my Register-action are NULL. I can't understand why..
Here Is my Register-action:
[HttpPost]
public async Task<ActionResult> Register(RegisterModel model)
{
if (!ModelState.IsValid)
{
return View();
}
var user = new AppUser
{
UserName = model.Email,
Country = model.Country
};
var result = await userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignIn(user);
return RedirectToAction("index", "home");
}
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error);
}
return View();
}
The actual issue is that you're using AuthenticationModel in the view and accepting RegistreModel in the action. You should accept AuthenticationModel in the action and the RegisterModel property will be populated.
If you make this change you can continue to use EditorFor which is better practice.
Easy Solution is to match the model properties by yourself
Do This
<input type="text" name="Email" id="Email" />
Remove This as
#Html.EditorFor(model => model.RegisterModel.Email)
Converts to
<input type="text" name="RegisterModel.Email" id="RegisterModel.Email" />
Which the default model binder cant match it to your proper fields

how to get selected drow down list value in Action?

In MVC web app it is a view with strongly typed model where a drop down is being generated / bind by model.
Below is view code:
#model LoanViewModel
<form class="wrapper minheight homeloan-form border-top" id="homeloan-form" method="post" action="LeadContact" novalidate="novalidate">
<p>#Html.ValidationSummary()</p>
<p>Select an Item : #Html.DropDownListFor(x => x.HomeLoanLead.Items, new SelectList(Model.HomeLoanLead.Items), "--Choose any Item--")</p>
<div class="formnav row">
<button class="">Show Top Home Loans <i class="fa fa-chevron-right"></i></button>
</div>
</form>
In model I m hardcoding options for drop down list:
public List<string> Items
{
get { _items = new List<string>();
_items.Add("One");
_items.Add("Two");
_items.Add("Three");
return _items;
}
}
On post back I cant get what was selected value in drop down. Please guide me how to get in post action which drop down value was selected.
A simple example of using Html.DropDownFor() to display a list of options and bind to a property:
Model
public class LoanViewModel
{
[Required]
[Display(Name="Select Item")]
public string Item { get; set; }
public SelectList ItemList { get; set; }
}
Controller
public ActionResult Edit()
{
LoanViewModel model = new LoanViewModel();
model.Item = "Two"; // this will now pre-select the second option in the view
ConfigureEditModel(model);
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(LoanViewModel model)
{
if (!ModelState.IsValid)
{
ConfigureEditModel(model); // repopulate select list
return View(model); // return the view to correct errors
}
// If you want to validate the the value is indeed one of the items
ConfigureEditModel(model);
if (!model.ItemList.Contains(model.Item))
{
ModelState.AddModelError(string.Empty, "I'm secure!");
return View(model);
}
string selectedItem = model.Item;
....
// save and redirect
}
private void ConfigureEditModel(LoanViewModel model)
{
List<string> items = new List<string>() { "One", "Two", "Three" };
model.ItemList = new SelectList(items); // create the options
// any other common stuff
}
View
#model LoanViewModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.DisplayFor(m => m.Item)
#Html.DropDownListFor(m => m.Item, Model.ItemList), "--Choose any Item--")
#Html.ValidationMessageFor(m => m.Item)
<input type="submit" value="Submit" />
}

saving text box string value to database c#

I have a textbox in which the user can enter their desired username and save it. Once they save it and they happen to revisit their profile page that textbox should be populated with the last username they saved to display and the user will still have the ability to change it and resave. I am fairly new to this and not sure how to start this properly. I am using vs 2012 asp.net mvc 4 c#. Here is my code so far:
#model School.Models.StudentNameModel
#using (Html.BeginForm("_StudentNamePartial", "Profile")) {
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<fieldset>
<ol>
<li>
#Html.LabelFor(m => m.StudentName)
#Html.DisplayFor(m => m.StudentName)
#Html.TextBoxFor(m=>m.StudentName)
<button type="button" value="save" />
</li>
</ol>
</fieldset>
}
This is my Model:
public class StudentNameModel
{
[Display(Name = "Student Name")]
public string StudentName{ get; set; }
}
My controller:
GET - To get the student name from database if one exists.
[HttpPost]
public ActionResult _StudentNamePartial(int id)
{
id = WebSecurity.CurrentStudentId;
var model = new StudentNameModel();
using (var db = new StudentsDataContext())
{
var result = (from u in db.Students
where u.ID == id
select u.StudentName).FirstOrDefault();
if(result != null)
model.StudentName= result;
}
return View(model);
}
POST - This is where i want to save the new username for the student
[HttpPost]
public ActionResult _StudentNamePartial(StudentNameModel model)
{
if (ModelState.IsValid)
{
using (var db = new StudentDataContext())
{
try
{
}
catch (Exception)
{
throw;
}
}
return RedirectToAction("ProfileAccount");
}
return View(model);
}
Also i am having trouble that when i am displaying the username it is not hitting my Action method and it always reports that the Object reference is null. Any help will be great. Thanks :D
It would seem that you're trying to render a partial view from a controller action as part of the larger view. In this case, the partial view should be rendered within the ProfileAccount view.
You can structure the controller and views like this (rough outline):
ProfileAccount View Model:
public class ProfileAccountView
{
public StudentNameModel StudentName { get; set; }
}
Profile Controller:
[HttpGet]
public ActionResult ProfileAccount(int id)
{
// Get whatever info you need and store in a ViewModel
var model = new ProfileAccountView();
// Get the student info and store within ProfileAccountView
// Do your database reads
model.StudentName = new StudentNameModel { StudentName = result };
return View(model);
}
[HttpPost]
public ActionResult ProfileAccount(ProfileAccountView profile)
{
// Do whatever processing here
}
ProfileAccount View
#model School.Models.ProfileAccountView
#using (Html.BeginForm("ProfileAccount", "Profile"))
{
#Html.RenderPartial('_StudentNamePartial', Model.StudentName);
<button type="button" value="save" />
}
_StudentNamePartial Partial View
#model School.Models.StudentNameModel
<fieldset>
<ol>
<li>
#Html.LabelFor(m => m.StudentName)
#Html.TextBoxFor(m=>m.StudentName)
</li>
</ol>
</fieldset>

Categories