I am trying to bind the grid (Kendo UI) with user entered values in TextBox, but when I start the program, I get an error like this,
Exception Details: System.InvalidOperationException: The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[KendoPratapSampleMVCApp.Models.EmployeeDetails]', but this dictionary requires a model item of type 'KendoPratapSampleMVCApp.Models.ParentViewModel'.
When the user entered the value in TextBox and then presses the submit button, the entered value needs to show in the grid.
This is my model,
namespace KendoPratapSampleMVCApp.Models
{
public class TextBoxGrid
{
public string EnteredValue { get; set; }
public List<EmployeeDetails> employees;
}
public class ParentViewModel
{
public EmployeeDetails EmployeeDetails { get; set; }
public TextBoxGrid TextBoxGrid { get; set; }
}
public class EmployeeDetails
{
public string EmployeeId { get; set; }
public string ManagerId { get; set; }
}
}
This is my controller (where i am binding the user entered value to grid)
namespace KendoPratapSampleMVCApp.Controllers
{
public class EnterValuesGridController : Controller
{
public ActionResult Index( TextBoxGrid model)
{
return View(GetEmployee());
}
[HttpPost]
public ActionResult PostValues(TextBoxGrid model)
{
TempData["enteringValue"] = model.EnteredValue;
return View(model);
}
public IEnumerable<EmployeeDetails> GetEmployee()
{
string enteredValueId =(string) TempData["enteringValue"];
string managerId = "M" +enteredValueId;
List<EmployeeDetails> empdtls = new List<EmployeeDetails>();
EmployeeDetails em1 = new EmployeeDetails();
em1.EmployeeId = enteredValueId;
em1.ManagerId = managerId;
empdtls.Add(em1);
return empdtls;
}
public ActionResult Orders_Read([DataSourceRequest]DataSourceRequest request)
{
return Json(GetOrders().ToDataSourceResult(request));
}
private IEnumerable<EmployeeDetails> GetOrders()
{
return GetEmployee();
}
}
}
And this is my view where I am displaying the grid,
#model KendoPratapSampleMVCApp.Models.ParentViewModel
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm("PostValues","EnterValuesGrid",FormMethod.Post))
{
#Html.TextBoxFor(m=>m.TextBoxGrid.EnteredValue)
<input type="submit" name="Submitbutton1" value="Submit1" />
#(Html.Kendo().Grid<KendoPratapSampleMVCApp.Models.ParentViewModel>()
.Name("grid")
.Columns(columns => {
columns.Bound(s=>s.EmployeeDetails.EmployeeId).Filterable(false).Width(100);
columns.Bound(s => s.EmployeeDetails.ManagerId).Filterable(false).Width(100);
})
.Pageable()
.Sortable()
.Scrollable()
.Filterable()
.HtmlAttributes(new { style = "height:430px;" })
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Read(read => read.Action("Orders_Read", "EnterValuesGrid"))
)
)
}
Would anyone please tell me why I am getting this error. How can I resolve this one?
EDIT : Changed postvalue method
[HttpPost]
public ActionResult PostValues(TextBoxGrid model)
{
TempData["enteringValue"] = model.EnteredValue;
var viewmodel = new ParentViewModel
{
TextBoxGrid = new TextBoxGrid { employees = GetEmployee().ToList() }
};
return View("Index", viewmodel);
}
when I submit the button it not showing the values in grid but its showing empty grid...
Error, because model of your view is ParentViewModel, but you give its with
return view(GetEmployee);
IEnumerable, so not corresponding object for model of view.
I advice you do it as follow
public ActionResult Index( TextBoxGrid model)
{
var viewModel = new ParentViewModel
{
TextBoxGrid = new TextBoxGrid { employees = GetEmployee().ToList()}
//but first change TextBoxGrid Property from emplyees to employees{get;set;}, second from return empdtls; to return empdtls.AsEnumarable();
}
return View(viewModel);
}
You must create PostValues view,, or change PostValues to Index, if its give you dublicat change you code as follow
[HttpPost]
public ActionResult PostValues(TextBoxGrid model)
{
TempData["enteringValue"] = model.EnteredValue;
return View("Index",model);
}
Related
I wish to utilize the ASP.NET MVC convention to parse POSTed form submission to a model by ActionResult MyAction(MyModel submitted). MyModel includes a property of the type that I defined -UsState-.
submitted.UsState as the result of the action returns null.
Is there any way to get the submitted to be set to proper value?
I have the following view with a form in a MyForm.cshtml
...
#using (Html.BeginForm("MyAction", "MyController", FormMethod.Post, ...))
{
#Html.DropDownList("States",
null,
new { #id = "state", #class = "form-control", #placeholder = "State"})
}
...
with the controller
public class MyController : Controller
{
public ActionResult MyForm()
{
ViewBag.States = GetStatesList();
}
public ActionResult MyAction(MyModel info) //info.State is set to null on POST
{
return View();
}
private static List<SelectListItem> GetStatesList()
{
var states = new List<SelectListItem>();
states.Add(new SelectListItem { Value = "", Selected = true, Text = "State" });
foreach (var s in UsStates.ToList())
{
var state = new SelectListItem { Value = s.Abbreviation, Text = s.Name, Disabled = !s.Available };
states.Add(state);
}
return states;
}
}
with the model
public class MyModel
{
public UsState States { get; set; } //Do I need proper setter for it to work?
}
public static class UsStates //Should I get the UsStates in a different way?
{
private static List<UsState> states = new List<UsState> {
new UsState("AL", "Alabama"),
//...
}
public static List<UsState> ToList()
{ return states; }
}
public class UsState
{
public UsState(string ab, string name, bool available = true)
{
Name = name;
Abbreviation = ab;
Available = available;
}
}
Change you MyModel to
public class MyModel
{
public string SelectedState {get;set; }
public IEnumerable<SelectListItem> States { get; set; }
}
modify your view to
#using (Html.BeginForm("MyAction", "MyController", FormMethod.Post, ...))
{
#Html.DropDownListFor(m => m.SelectedState, Model.States, "State",
new { #class = "form-control" })
}
I changed this to a DropDownListFor, because it will automatically generate the id and name attributes for you. It will also create an element at the top "State" so that you don't have to pre-pend it to your list.
I removed your placeholder because placeholders are not supported with select elements. As well as not to be used as replacements for labels.
Per W3C
The placeholder attribute specifies a short hint that describes the
expected value of an input field (e.g. a sample value or a short
description of the expected format).
Split your controller actions to a GET/POST pair
public class MyController : Controller
{
//Get
public ActionResult MyAction()
{
return View(new MyModel { States = GetStateList() });
}
[HttpPost]
public ActionResult MyAction(MyModel model)
{
if (!ModelState.IsValid)
{
model.States = GetStateList();
return View(model);
}
//do whatever you are going to do with the posted information.
return RedirectToAction("<some view>"); //redirect after a post usually to Index.
}
private static IEnumerable<SelectListItem> GetStatesList()
{
var states = new List<SelectListItem>();
foreach (var s in UsStates.ToList())
{
var state = new SelectListItem { Value = s.Abbreviation, Text = s.Name, Disabled = !s.Available };
states.Add(state);
}
return states;
}
}
After looking into the POSTed data, I realized that the submitted form data -States=AL-type is string, which would fail to be set as UsState type.
I changed the model to the following:
public class MyModel
{
public string States { get; set; }
}
I get the string value of the submitted form, at least. Not sure if this is given - if that's the case, I suppose I should use a separate ViewModel in order to get States as a string, and convert that into MyModel where I cast string States into UsState States.
How to pass SelectedItem from DropDownListFor to public ActionResult Index(IndexViewModel indexViewModel). After submit i have emp=null.
What i should place instead of "Number" in IndexViewModel.ListOfEmployee = new SelectList(ListOfEmployee, "Number", "Name");
Controller:
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
List<Employee> ListOfEmployee = new List<Employee>();
ListOfEmployee.Add(new Employee { Name = "Jhon", Number = 1 });
IndexViewModel IndexViewModel = new IndexViewModel();
IndexViewModel.ListOfEmployee = new SelectList(ListOfEmployee, "Number", "Name");
return View(IndexViewModel);
}
[HttpPost]
public ActionResult Index(IndexViewModel indexViewModel)
{
return View();
}
}
View:
#model MvcApplication3.Models.IndexViewModel
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using(#Html.BeginForm())
{
#Html.DropDownListFor(model=>model.emp ,Model.ListOfEmployee)
<input type="submit" />
}
Model:
public class IndexViewModel
{
public SelectList ListOfEmployee { get; set; }
public Employee emp { get; set; }
}
You should keep a simple value type property to store the selected dropdown option value.
public class IndexViewModel
{
public SelectList ListOfEmployee { get; set; }
public int SelectedEmployeeId { get; set; }
}
and in your view
#Html.DropDownListFor(x=>x.SelectedEmployeeId, Model.ListOfEmployee)
and in your HttpPost action, access this SelectedEmployeeId property which will give you the number corresponding to the selected name. If you want the complete employee object, you should query the db again with the number(id)
[HttpPost]
public ActionResult Index(IndexViewModel model)
{
var selectedNumber= model.SelectedEmployeeId;
return View();
}
I'm trying to get a dropdown show the right value when editing using a viewmodel but it only works when i pass the complete model to the view.
When I do it like this and there is already a contact selected it shows that contact in the edit screen.
Model
public class ClientModel
{
public int ID { get; set; }
public int ContactID { get; set; }
//Other atributes
}
View EditContact
#model Project.Models.ClientModel
#Html.DropDownListFor(model => model.ContactID , (SelectList)ViewBag.ContactID, "select a contact")
Controller
public ActionResult EditContact(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var Contact = db.Contacts.ToList();
ViewBagID.Contact = new SelectList(Contact.AsEnumerable(), "ID", "name", "Contact");
ClientModel model= db.ClientModel.Find(id);
return View(model);
}
But when I do it like this and there is already a contact selected the dropdownlist shows select contact.
Model
public class ClientModel
{
public int ID { get; set; }
public int ContactID { get; set; }
//Other atributes
}
ViewModel
public class ClientEditContactModel
{
public int ID { get; set; }
public int ContactID { get; set; }
}
View EditContact
#model Project.Models.ClientEditContactModel
#Html.DropDownListFor(model => model.ContactID, (SelectList)ViewBag.ContactID, "select a contact")
Controller
public ActionResult EditContact(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var Contact = db.Contacts.ToList();
ViewBag.ContactID = new SelectList(Contact.AsEnumerable(), "ID", "name", "Contact");
ClientModel client= db.ClientModel.Find(id);
ClientEditContactModel model = new ClientEditContactModel();
model.ID = client.ID;
model.ContactID = client.ContactID
return View(model);
}
How do i fix this with the viewmodel?
Edit
I've made some typo's in my code so I fixed them but because of them i found the answer see below.
I found the answer after some more research here https://stackoverflow.com/a/11949123/4252392.
The problem was that ViewBag's name is the same as the model's property.
So i changed the Viewbag's name.
New Controller
public ActionResult EditContact(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var Contact = db.Contacts.ToList();
ViewBag.ContactIDList = new SelectList(Contact.AsEnumerable(), "ID",
"name", "Contact");
ClientModel client= db.ClientModel.Find(id);
ClientEditContactModel model = new ClientEditContactModel();
model.ID = client.ID;
model.ContactID = client.ContactID
return View(model);
}
New View
#model Project.Models.ClientEditContactModel
#Html.DropDownListFor(model => model.ContactID, (SelectList)ViewBag.ContactIDList,
"select a contact")
If you set selected value in ContactID property from dropdown so you need to set dropdown in view like below:
#model Project.Models.ClientEditContactModel
#Html.DropDownListFor(model => model.ContactID, (SelectList)ViewBag.Contact,
"select a contact")
My COntroller class;
in the following example returnAllHuman(); will return List<SelectListItem>
public ActionResult Index()
{
var list = returnAllHuman(); // List<SelectListItem>
ViewData["all_Human"] = list;
return View();
}
In the View
#Html.DropDownList("all_Human")
1.) The values don't get displayed
2.) I need to grab the selected value and display it in a text field. How can i do this ?
UPDATE: I removed the exception handling part from the below code
public List<SelectListItem> returnAllHuman()
{
var i = new List<SelectListItem>();
using (SqlCommand com = new SqlCommand("SELECT * FROM Names", con))
{
con.Open();
SqlDataReader s = com.ExecuteReader();
while (s.Read())
{
i.Add(new SelectListItem
{
Value = s.GetString(0),
Text = s.GetString(1)
});
}
con.Close();
return i;
}
Start by defining a view model:
public class MyViewModel
{
[Required]
public string SelectedHuman { get; set; }
public IEnumerable<SelectListItem> AllHumans { get; set; }
}
and then have your controller populate this model and pass to the view:
public class HomeController: Controller
{
public ActionResult Index()
{
var model = new MyViewModel();
model.AllHumans = returnAllHuman(); // List<SelectListItem>
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
if (!ModelState.IsValid)
{
// there was a validation error => for example the user didn't make
// any selection => rebind the AllHumans property and redisplay the view
model.AllHumans = returnAllHuman();
return View(model);
}
// at this stage we know that the model is valid and model.SelectedHuman
// will contain the selected value
// => we could do some processing here with it
return Content(string.Format("Thanks for selecting: {0}", model.SelectedHuman));
}
}
and then in your strongly typed view:
#model MyViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(x => x.SelectedHuman, Model.AllHumans, "-- Select --")
#Html.ValidationFor(x => x.SelectedHuman)
<button type="submit">OK</button>
}
I have a page that has two drop down lists and based upon the selection of these two lists I would like to populate a textarea with some data on submit button press.
The behavior that I am seeing while debugging is that the page is rendered, I make my selections and press submit. The DataAccess returns the correct results and the View returns, but with an exception "There is no ViewData item of type 'IEnumerable' that has the key 'People'.
I can see that I could re-setup the drop down lists, but it feels like I'm approaching this incorrectly. Is there another approach for doing this sort of action in MVC 3?
public ActionResult Test()
{
//People for dropdownlist 1
var db = peopleRepository.People;
var query = db.Select(c => new {c.Id, c.Name});
ViewBag.People = new SelectList(query.AsEnumerable(), "Id", "Name");
//Elements for dropdownlist 2
var list = new Dictionary<string, string> {{"1", "Name"}, {"2", "Address"}, {"3", "Zip"}};
ViewBag.Elements = new SelectList(list, "Key", "Value");
return View();
}
// This part is what I'm confused about.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Test(string people, string elements)
{
if (ModelState.IsValid)
{
// Output from persistent storage query
var da = new DatabaseAccess(people, elements);
ViewBag.Results = da.Execute();
}
return View();
}
View:
#using (Html.BeginForm("Test", "Home", FormMethod.Post))
{
#Html.DropDownList("People", (SelectList)ViewBag.People, "--Select One--")
#Html.DropDownList("Elements", (SelectList)ViewBag.Elements, "--Select One--")
#Html.TextArea("Results", (string)ViewBag.Results, 10, 120, "")
}
Here is how I would quickly construct it :
Model :
public class People
{
public int Id { get; set; }
public string Name { get; set; }
}
ViewModel (everything needed by the view):
public class TestViewModel
{
public int SelectedPeopleId { get; set; }
public string SelectedElementId { get; set; }
public SelectList People { get; set; }
public SelectList Elements { get; set; }
public String Results { get; set; }
}
Controller (used Index as the default Action, create an init function for the view model that can be adapted)to anything more appropriate :
public class HomeController : Controller
{
private static TestViewModel InitTestVM()
{
//People for dropdownlist 1
var db = new List<People>();//peopleRepository.People;
db.Add(new People { Id = 1, Name = "Name 1" });
db.Add(new People { Id = 2, Name = "Name 2" });
var query = db.Select(c => new { c.Id, c.Name });
//Elements for dropdownlist 2
var list = new Dictionary<string, string> { { "1", "Name" }, { "2", "Address" }, { "3", "Zip" } };
TestViewModel testVM = new TestViewModel
{
People = new SelectList(query.AsEnumerable(), "Id", "Name"),
Elements = new SelectList(list, "Key", "Value")
};
return testVM;
}
public ActionResult Index()
{
return View(InitTestVM());
}
// This part is what I'm confused about.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(TestViewModel testVM)
{
var vm = InitTestVM();
if (ModelState.IsValid && testVM != null)
{
ModelState.Clear();
// Output from persistent storage query
//var da = new DatabaseAccess(people, elements);
vm.Results = "sfdfsdfsdfsdfsdfsdfsdfsdf";//da.Execute();
vm.SelectedElementId = testVM.SelectedElementId;
vm.SelectedPeopleId = testVM.SelectedPeopleId;
return View(vm);
}
return View(vm);
}
}
And finally the View :
#model ViewModels.TestViewModel
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
#Html.DropDownListFor(m => m.SelectedPeopleId, Model.People, "--Select One--")
#Html.DropDownListFor(m => m.SelectedElementId, Model.Elements, "--Select One--")
#Html.TextAreaFor(m => m.Results, 10, 120, "")
<input type="submit" value="Test" />
}