I am developing an ASP.net MVC application with EF Scaffolding using the code first approach. One of the view using Kendo MultiSelect is unable to load the items. At run time, the MultiSelect only displays the text "undefined".
Here is the Model
public class SessionStudent
{
public int SessionStudentID { get; set; }
public int SessionID { get; set; }
[Display(Name = "Session")]
public virtual Session Session { get; set; }
public IEnumerable<int> SelectedStudentIDs { get; set; }
public IEnumerable<Student> Student { get; set; }
public int GradeID { get; set; }
[Display(Name = "Grade")]
public virtual Grade Grade { get; set; }
}
Here is the Get and Post methods in Controller
// GET: SessionStudents/Create
public ActionResult Create()
{
ViewBag.GradeID = new SelectList(db.Grades, "GradeID", "GradeName");
ViewBag.SessionID = new SelectList(db.Sessions, "SessionID", "SessionName");
ViewBag.StudentID = new SelectList(db.Students, "StudentID", "FName");
return View();
}
// POST: SessionStudents/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "SessionStudentID,SessionID,GradeID")] SessionStudent sessionStudent)
{
if (ModelState.IsValid)
{
db.SessionStudents.Add(sessionStudent);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.GradeID = new SelectList(db.Grades, "GradeID", "GradeName", sessionStudent.GradeID);
ViewBag.SessionID = new SelectList(db.Sessions, "SessionID", "SessionName", sessionStudent.SessionID);
return View(sessionStudent);
}
And here is the MultiSelect in the view
<div class="form-group">
#Html.LabelFor(model => model.SessionStudentID, "StudentID", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.Kendo().MultiSelectFor(model => model.SessionStudentID).BindTo((SelectList)ViewBag.StudentID).DataTextField("FName").DataValueField("StudentID").Name("SelectedStudentIDs")
#Html.ValidationMessageFor(model => model.SessionStudentID, "", new { #class = "text-danger" })
</div>
</div>
Any help in this regard is highly appreciated.
The problem is a misunderstanding of the SelectList contruction.
When you create a SelectList with
ViewBag.StudentID = new SelectList(db.Students, "StudentID", "FName");
"StudentID" and "FName" are the mapping fields in the db.Students collection, NOT the accessor field names in the SelectList.
The SelectList will still contain items with "Text" and "Value" fields mapped from "FName" and "StudentID".
So, when you then bind the MultiSelect to
#Html.Kendo().MultiSelectFor(model => model.SessionStudentID)
.BindTo((SelectList)ViewBag.StudentID)
.DataTextField("FName")
.DataValueField("StudentID")
.Name("SelectedStudentIDs")
You are saying "Bind to the list ViewBag.StudentID with "FName" as the text field and "StudentID" as the value field.
BUT ViewBag.StudentID is a SelectList, which uses Text and Value by definition.
Removing the DataTextField and DataValueField specifiers should fix it for you, as then the MultiSelectFor will use the defaults of "Text" and "Value".
You would only need to use the DataTextField and DataValueField if you BindTo() an arbitrary Enumerable that didn't use Text and Value as the accessors, i.e. if you didn't convert db.Students to a SelectList such that ViewBag.StudentID was an IEnumerable, then you would need to tell the MultiSelect to use FName and StudentID to access the items in the bound enumerable.
Related
I can get all Roles plus actually Role for chosed user, but then When I posting to EditUser action, then Dropdownlist sends null.
I mean When the form posts to my controller, I get null from DropDownList.
Here is my Model
public class EditUserViewModel
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public List<SelectListItem> ApplicationRoles { get; set; }
public string ApplicationRoleId { get; set; }
}
Here is Action
[HttpGet]
public async Task<ActionResult> EditUser(string id)
{
EditUserViewModel model = new EditUserViewModel();
model.ApplicationRoles = RoleManager.Roles.Select(r => new SelectListItem
{
Text = r.Name,
Value = r.Id
}).ToList();
if (!String.IsNullOrEmpty(id))
{
ApplicationUser user = await UserManager.FindByIdAsync(id);
if (user != null)
{
var role = await UserManager.GetRolesAsync(user.Id);
var existingRole = role.First();
string existingRoleId = RoleManager.Roles.Single(r => r.Name == existingRole).Id;
model.Id = user.Id;
model.FirstName = user.FirstName;
model.ApplicationRoleId = existingRoleId;
ViewBag.RoleId = new SelectList(RoleManager.Roles, "Id", "Name", model.ApplicationRoleId);
}
}
return PartialView("_EditUser", model);
}
And here is DropDownlist from _EditUser.cshtml
<div class="form-group">
#Html.Label("Role typ", htmlAttributes: new { #class = "control-label col-md-6" })
<div class="col-md-12" title="Ange antal datorer som finns i lager">
#Html.DropDownList("RoleId", null, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.ApplicationRoles, "", new { #class = "text-danger" })
</div>
</div>
Getting null Only from DropDownList, not from #Html.EditorFor
/Thanks in advance!
Forms post back the name/value pairs of their successful form controls. Your generating a <select> element with name="RoleId" but you model does not contain a property named RoleId. Since you want to bind the selected option to the ApplicationRoleId role property, then you view needs to be
#Html.LabelFor(m => m.ApplicationRoleId)
#Html.DropDownListFor(m => m.ApplicationRoleId, Model.ApplicationRoles)
#Html.ValidationMessageFor(m => m.ApplicationRoleId)
Notes:
Your current #Html.Label(..) code does not create a label
associated with your dropdownlist (clicking on it will not set
focus)
The ValidationMessageFor() need to be applied to the property your
binding to, not the SelectList
Delete you ViewBag.RoleId = new SelectList(..) code. Your have
already assigned the selectlist to the ApplicationRoles property
(and you should never need ViewBag if have a view model anyway)
Because you are declare that only HttpGet methods are allow in that method of the controller. Thats why
I am using MVC Entity framework i have generated code i have fields Isactive this fields have values true or false . code looks like
controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="ClientId,ClientName,PrimaryContactName,EmailId,PrimaryContact,IsActive,ModifiedBy,ParentCompany")] TP_InternalClients tP_InternalClients)
{
if (ModelState.IsValid)
{
db.Entry(tP_InternalClients).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(tP_InternalClients);
}
model:
public class InternalClients
{
public int ClientId { get; set; }
public string ClientName { get; set; }
public string PrimaryContactName { get; set; }
public string EmailID { get; set; }
public string PrimaryContact { get; set; }
public bool IsActive { get; set; }
public string ModifiedBy { get; set; }
public int ParentCompany { get; set; }
}
View:
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.IsActive)
#Html.ValidationMessageFor(model => model.IsActive, "", new { #class = "text-danger" })
</div>
</div>
after run the code Isactive drop down showing true or false i want hidden field that time send value default true only to database . how i can hidden and send value default ? i doing i am getting error
In your form , simply replace
<div class="checkbox">
#Html.EditorFor(model => model.IsActive)
#Html.ValidationMessageFor(model => model.IsActive, "", new { #class = "text-danger" })
</div>
with
<input type="hidden" name="IsActive" value="true" />
Or you can use the Html helper method
#Html.HiddenFor(s=>s.IsActive)
Now make sure you set the default value to whatever you want in the GET action.
But, If you want a default value to be saved, Do it in your HttpPost action, No need to keep the Hidden field in the form (Users can update the hidden field value using browser dev tools)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="ClientId,ClientName,PrimaryContactName,EmailId,
PrimaryContact,ModifiedBy,ParentCompany")] TP_InternalClients model)
{
if (ModelState.IsValid)
{
model.IsAcive = true ;
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(tP_InternalClients);
}
Remember, the best way to prevent overposting is to use a view model with only those properties needed for the view.
I have a partial view I want to display as a search interface. Every time it tells me I get the error
There is no ViewData item of type IEnumerable that has the key resource_type_id.
I have tried so many things to make this work but nothing helps.
This is my view calls the partialview
#model IEnumerable<NewSAMACentral2._0.ViewModel.MemberResourcesViewModel.MemberResource>
#{
ViewBag.Title = "Add Resource To Folder";
}
<h2>Add Resource To Folder</h2>
<div>
#{Html.Partial("SearchResource", new NewSAMACentral2._0.ViewModel.MemberResourcesViewModel.ResourceSearch());}
</div>
#using (Ajax.BeginForm("InsertAttendee", "Meetings", new AjaxOptions { HttpMethod = "POST" }))
{
if (Model.Any())
{
}
}
This is my partialview
#model NewSAMACentral2._0.ViewModel.MemberResourcesViewModel.ResourceSearch
#using (Ajax.BeginForm("AddAttendee", "Meetings", new AjaxOptions { UpdateTargetId = "AddAttendee", HttpMethod = "POST" }))
{
<div class="form-group">
<label for="keyword">Keyword(s): </label>#Html.TextBox("keyword", null, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(model => Model.resource_type_id)
#Html.DropDownListFor(model => Model.resource_type_id, Model.resource_type, "-- Select --", new { #class = "form-control" })
</div>
<div class="form-group">
<label for="author">Author(s): </label>#Html.TextBox("author", null, new { #class = "form-control" })
</div>
<div class="form-group">
<input type="submit" name="submit" value="Search" />
</div>
}
This is the controller that never seems to get called...
public PartialViewResult SearchResource()
{
var results = new MemberResourcesViewModel.ResourceSearch();
results.resource_type = db.Resource_Types.Select(s => new SelectListItem
{
Text = s.name,
Value = s.id.ToString()
}).Distinct().OrderBy(x => x.Text);
return PartialView(results);
}
This is the ViewModel
namespace NewSAMACentral2._0.ViewModel
{
public class MemberResourcesViewModel
{
public IEnumerable<MemberResource> MemberResourceResult;
public MemberResource memberResource;
public class MemberResource
{
public ResourceSearch resource_search { get; set; }
[Key]
public int Id { get; set; }
[DisplayName("Resource Title")]
public string title { get; set; }
public IEnumerable<SelectListItem> resource_type { get; set; }
[DisplayName("Resource Type")]
public string resource_type_id { get; set; }
[DisplayName("Keyword")]
public string keyword { get; set; }
[DisplayName("Author")]
public string author { get; set; }
[DisplayName("Subject Type")]
public string subject_type { get; set; }
[DisplayName("Industry")]
public string industry { get; set; }
[DisplayName("Description")]
public string description { get; set; }
}
public class ResourceSearch
{
[DisplayName("Author")]
public string author { get; set; }
public IEnumerable<SelectListItem> resource_type { get; set; }
[DisplayName("Resource Type")]
public string resource_type_id { get; set; }
[DisplayName("Keyword")]
public string keyword { get; set; }
}
}
}
You have to be carefull with capital letters and put model not Model:
#Html.LabelFor(model => model.resource_type_id)
#Html.DropDownListFor(model => model.resource_type_id, model.resource_type, "-- Select --", new { #class = "form-control" })
On your main View Action (not partial view action result):
var types = db.Resource_Types.Distinct().OrderBy(x => x.Text).ToList();
SelectList typeList = new SelectList(types, "ID", "Name");
ViewBag.Types = typelist;
All that was done there was pull your objects from the DataBase. Then we turned that into a Select list with 'ID' as the value field and 'Name' as the text field. Then we put that select list in a viewbag to be used by our view.
Next In your partial view:
#Html.DropDownListFor(model => model.resource_type_id, new SelectList(ViewBag.Types, "value", "text"), "-- Select --", new { #class = "form-control" })
The only difference in this HTML is its pulling values from the select list so you never have to worry about it even hitting the partial view controller. I also changed the capital 'M' in model to a lowercase because not needed
Remember to put the code for the ViewBag in your main actionresult, not the partial view action result.
As Stephen commented below all you really need is :
#Html.DropDownListFor(model => model.resource_type_id, (SelectList)ViewBag.Types, "-Select-", ...)
Your error occurs because the value of Model.resource_type is null when used inside the DropDownListFor() method.
In your main view you use Html.Partial() to render a partial view named SearchResource.cshtml, passing it a new instance of your class ResourceSearch. But ResourceSearch does not have a default constructor which initializes the resource_type property so its null, hence the exception.
Your naming conventions and use of nested models make it difficult to understand, and you have not shown the GET method for the main view, but I suspect you are wanting to actually call the SearchResource() method on your controller which will return the partial view of the form. In which case you need to use
#{Html.RenderAction("SearchResource")}
which will call the method and return its partial. Since that method initializes a new instance of ResourceSearch and populates its resource_type property, it will no longer be null
Note you should also consider applying the [ChildActionOnly] attribute to the method so it cant be called by the user entering the url in the address bar.
I've encountered some problems using DropDownList in ASP.NET MVC lately.
I want to save value of selected item to member called Wydzialy.
Sorry for not translating some names, they doesn't matter I think :)
Here is what I have:
View:
<div class="form-group">
#Html.LabelFor(model => model.Wydzial, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.Wydzial, (List<SelectListItem>)ViewBag.Wydzialy)
</div>
</div>
Model:
public class Student
{
public int Id { get; set; }
public int NumerIndeksu { get; set; }
public string Imie { get; set; }
public string Nazwisko { get; set; }
public int Semestr { get; set; }
public virtual Wydzial Wydzial { get; set; }
}
Controller:
public ActionResult Create()
{
var wydzialy = db.Wydzialy.ToList();
var lista = wydzialy.Select(W => new SelectListItem()
{
Text = W.Nazwa
}).ToList();
ViewBag.Wydzialy = lista;
return View();
}
Your trying to bind the dropdown to a complex object. A <Select> only posts backs a value type (in your case the text of the selected option).
Either bind to a property of Wydzial
#Html.DropDownListFor(x => x.Wydzial.Nazwa, (List<SelectListItem>)ViewBag.Wydzialy)
or preferably use a view model that includes a property to bind to and the SelectList
public class StudentVM
{
public int Id { get; set; }
// Other properties used by the view
public string Wydzial { get; set; }
public SelectList Wydzialy { get; set; }
}
Controller
public ActionResult Create()
{
StudentVM model = new StudentVM();
model.Wydzialy = new SelectList(db.Wydzialy, "Nazwa", "Nazwa")
return View(model );
}
View
#model StudentVM
....
#Html.DropDownListFor(x => x.Wydzial, Model.Wydzialy)
Note you appear to be binding only to the Nazwa property of Wydzial. Typically ou would display a text property but bind to an ID property.
I have a mvc3 dropdownlist containing Organization list.I am able to fill that using the code below.But when I submit the form, I am getting Id instead of name and the corresponding Id is null.
Controller
ViewBag.DropDownList =organizationModelList.Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() });
return view();
Model
public class SubscriberModel
{
public OrgnizationList Organization { get; set; }
public RegisterModel RegisterModel { get; set; }
public SubscriberDetails SubscriberDetails { get; set; }
}
public class OrgnizationList
{
[Required]
public ObjectId Id { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Name")]
public string Name { get; set; }
}
View
#
model FleetTracker.WebUI.Models.SubscriberModel
#using (Html.BeginForm((string)ViewBag.FormAction, "Account")) {
<div>
#Html.DropDownListFor(m => m.Organization.Name, (IEnumerable<SelectListItem>)ViewBag.DropDownList, "---Select a value---")
</div>
}
When I change it tom => m.Organization.Id, then the modelstate will change to not valid.
Do you really need the name to be returned instead of the Id? If yes then instead of this:
ViewBag.DropDownList =organizationModelList.Select(x => new
SelectListItem { Text = x.Name, Value = x.Id.ToString() });
do this:
ViewBag.DropDownList =organizationModelList.Select(x => new SelectListItem { Text = x.Name, Value = x.Name });
Then remove the Required attribute for OrgnizationList.Id. If OrgnizationList is an entity, which I think it is, then you'll run yourself into trouble. I suggest you have a viewmodel that represents your input. So you don't have to deal with unnecessary required fields.
But what if the Name is not unique? Why can't you just accept the Id and save it in your data store? You are not modifying the name of OrgnizationList, I assume.
UPDATE:
If you really need both then tuck the Id on a hidden field:
Your controller method
ViewBag.DropDownList =organizationModelList.Select(x => new SelectListItem { Text = x.Name, Value = x.Id });
Your model
public class SubscriberModel
{
public int OrganizationId { get; set; }
// your other properties goeshere
}
Your view
<div>
#Html.HiddenFor(m=>m.OrganizationId)
#Html.DropDownListFor(m => m.Organization.Name, (IEnumerable<SelectListItem>)ViewBag.DropDownList, "---Select a value---")
</div>
and a bit of js needed...
$("Organization_Name").change(function(){
$("#OrganizationId").val($(this).val());
});
I did it using
$(document).ready(function () {
$("#DropDownList").change(function () {
$("#Organization_Id").val($(this).val());
$("#Organization_Name").val($("#DropDownList option:selected").text());
});
});
#Html.HiddenFor(m=>m.Organization.Id)
#Html.HiddenFor(m=>m.Organization.Name)
#Html.DropDownList("DropDownList", string.Empty)
controller
ViewBag.DropDownList = new SelectList(organizationModelList, "Id", "Name");