Mvc3 DropdownlistFor error - asp.net-mvc

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");

Related

Problem in showing ViewModel in Create form

I am learning how to use ViewModel to show the fields from 2 different models. I have one model containing the MsgTypeId, MsgType and MsgStatus and the another model OptStatus containing the StatusId, StatusName and StatusValue. The MsgStatus will be shown in form of drop down list and show all the values in OptStatus. Both models have a separate database table to store their values.
namespace theManager.Areas.Settings.Models
{
public class OptStatus
{
[Required]
[Key]
public int StatusId { get; set; }
[Required]
public string StatusName { get; set; }
[Required]
public char StatusValue { get; set; }
}
}
namespace theManager.Areas.Settings.Models
{
public class OptMsgType
{
[Required]
[Key]
public int MsgTypeId { get; set; }
[Required]
public string MsgType { get; set; }
[Required]
public string MsgStatus { get; set; }
}
}
I have created a ViewModel to show these fields in the Create form of OptMsgType. However, when I run the code, I got an error
"System.NullReferenceException: 'Object reference not set to an instance of an object.'"
I would like to ask if there is something wrong with my ViewModel. Thanks!
namespace theManager.Areas.Settings.ViewModels
{
public class OptMsgTypeCreateViewModel
{
public OptMsgType OptMsgType { get; set; }
public IEnumerable<SelectListItem> OptStatuses { get; set; }
}
}
OptMsgTypeController.cs
public IActionResult Create(int id)
{
var OptMsgTypeViewModel = new OptMsgTypeCreateViewModel();
OptMsgTypeViewModel.OptStatuses = _context.OptStatus.ToList().Select(x => new SelectListItem
{
Text = x.StatusName,
Value = x.StatusValue.ToString()
});
OptMsgTypeViewModel.OptMsgType = _context.OptMsgType.Where(a => a.MsgTypeId == id).FirstOrDefault();
//var v = _context.OptMsgType.Where(a => a.MsgTypeId == id).FirstOrDefault();
return View(OptMsgTypeViewModel);
}
I have problems in displaying the Create form which will show the fields declared in the ViewModel.
#model theManager.Areas.Settings.ViewModels.OptMsgTypeCreateViewModel
#{
ViewData["Title"] = "Create";
Layout = null;
}
<h2>Message Type Settings</h2>
#using (Html.BeginForm("Create","OptMsgType", FormMethod.Post, new { id= "popupForm" }))
{
if (Model != null && Model.OptMsgType.MsgTypeId > 0)
{
#Html.HiddenFor(a=>a.OptMsgType.MsgTypeId)
}
<div class="form-group">
<label>Message Type ID</label>
#Html.TextBoxFor(a=>a.OptMsgType.MsgTypeId,new { #class = "form-control" })
#Html.ValidationMessageFor(a=>a.OptMsgType.MsgTypeId)
</div>
<div class="form-group">
<label>Leave Type</label>
#Html.TextBoxFor(a => a.OptMsgType.MsgType, new { #class = "form-control" })
#Html.ValidationMessageFor(a => a.OptMsgType.MsgType)
</div>
<div class="form-group">
<label>Status</label>
#Html.DropDownListFor(model => model.OptStatuses, new SelectList(Model.OptStatuses, "Value", "Text"), htmlAttributes: new { #class = "form-control", id = "OptStatus" })
#Html.ValidationMessageFor(a => a.OptStatuses)
</div>
<div>
<input type="submit" value="Create" />
</div>
}
The System.NullReferenceException indicates that you are using a field without initializing it. It coulbe a problem with your view model or it could be a problem anywere else. For example from the code smaple is not possible to see where you initialize the context you are using to get the data, and that could be the cause of the exception you are getting.
Either way I would advise you to pay attention to yout IDE, it usualy indicates in which line adnd class the exception is being thown. If you navigate to that class at that line you will easily identify which field can be de cause of the exception.
Regarding your view model, its considered a good practice to always initialize the lists on your model on the constructor of your class. This way you can guarantee that they are already initialized when you try to use them.
So my sugestion would be to initialize your list on the constructor of your viewmodel
public OptMsgTypeCreateViewModel()
{
OptStatuses = new List<OptStatus>();
}
#George, thanks for the reply. Please try this then: instantiate your class in the viewmodel.
public class OptMsgTypeCreateViewModel
{
public OptMsgTypeCreateViewModel()
{
OptMsgType = new OptMsgType();
}
public OptMsgType OptMsgType { get; set; }
public IEnumerable<SelectListItem> OptStatuses { get; set; }
}
hi in action controller you should change this code:
OptMsgTypeViewModel.OptStatuses = _context.OptStatus.ToList().Select(x => new SelectListItem
{
Text = x.StatusName,
Value = x.StatusValue.ToString()
});
I think _context.OptStatus.ToList() in null so you get this exception. change code to this:
OptMsgTypeViewModel.OptStatuses =new list<SelectListItem>();
var temp= _context.OptStatus.ToList();
if(temp!=null&&temp.count()>0)
{
OptMsgTypeViewModel.OptStatuses = temp.Select(x => new SelectListItem
{
Text = x.StatusName,
Value = x.StatusValue.ToString()
}).tolist();
}
EDIT:
I think this object "Model.OptMsgType" is null
change code in view like this:
if (Model != null && Model.OptMsgType!=null && Model.OptMsgType.MsgTypeId > 0)
{
#Html.HiddenFor(a=>a.OptMsgType.MsgTypeId)
}

Unable to load items into Kendo().MultiSelect

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.

Model binding not working properly for Sitecore.Data.ID type while submitting through a Form

I am experiencing a model binding problem, My id is of type Sitecore.Data.ID. After submitting the form, all the other fields gets bonded with correct data, however my Id gets changed to something else.
For example, in the form, the value for hidden field 'id' is 2fb3169c-8b3f-4618-ac78-6170fd0eb297, after submitting to CartController, the value becomes {{68CE2980-7611-422B-96E1-29C4CC0132D5}} or {{82F7914C-34D6-4009-B301-53C1499774A3}} or something else.
I think its random. I am not sure where I going wrong.
I have a Model like this:
[SitecoreType(AutoMap = true,Cachable = true)]
public class Book : Item
{
public virtual ID Id { get; set; }
[SitecoreField(IsRequired = true)]
public virtual string Name { get; set; }
[SitecoreField(IsRequired = true)]
public virtual double Price { get; set; }
[SitecoreField(IsRequired = true)]
[StringLength(50, MinimumLength = 5)]
public virtual string Description { get; set; }
}
This is my view:
#model Book
using (Html.BeginRouteForm(Sitecore.Mvc.Configuration.MvcSettings.SitecoreRouteName, FormMethod.Post)
)
{
#Html.Sitecore().FormHandler("Cart", "Index")
#Html.HiddenFor(x => Model.Id)
<div>
#Html.DisplayFor(x => book.Name)
#Html.EditorFor(x => book.Name, new { #class = "bold" })
</div>
<div>
#Html.DisplayFor(x => book.Price)
#Html.EditorFor(x => book.Price, new { #class = "bold" })
</div>
<div>
#Html.DisplayFor(x => book.Description)
#Html.EditorFor(x => book.Description, new { #class = "bold" })
</div>
<input type="submit" />
}
This is the cart controller:
public class CartController : GlassController
{
[HttpPost]
public ActionResult Index(Book book)
{
string id = book.Id.ToString();
if (!string.IsNullOrEmpty(id))
{
book = SitecoreContext.GetItem<Book>(new Guid(id), false, true);
return PartialView("~/Views/Cart/details.cshtml", book);
}
return Redirect("http://google.com");
}
}
The Id represents the item Id in the glass mapper. So, instead of using
public virtual ID Id { get; set; }
change it to this one:
[SitecoreId]
public virtual Guid Id { get; set; }

how can i get the selected text from dropdownlistfor

i have a model :
public class studentmodel
{
public int id { get; set; }
public string name { get; set; }
}
i populate my dropdown :
// GET: dropdown/Test
public ActionResult Index()
{
List<SelectListItem> list = new List<SelectListItem>();
{
list.Add(new SelectListItem { Text = "saurav", Value = "1"});
list.Add(new SelectListItem {Text = "Rj", Value = "2" });
list.Add(new SelectListItem {Text = "rahul", Value = "3" });
ViewBag.studentlist = list;
}
return View();
}
[HttpPost]
public ActionResult Index(studentmodel s)
{
return View();
}
i have a controller action which is postback:
#using (Html.BeginForm("Index", "Test", FormMethod.Post))
{
#Html.DropDownListFor(m => m.name, (IEnumerable<SelectListItem>)ViewBag.studentlist, "select student");
<div>
<input type="submit" value="submit" />
</div>
<div> you have selected : #ViewBag.selected </div>
}
How do i get the text from my drop down list? Thanks
You need to use client side javascript as the change happens at the browser.
First change the markup a little bit to wrap the selection in a span.
<div> you have selected : <span id="selectedItem">#ViewBag.selected</span> </div>
Remove the #ViewBag.selected from the above line if your GET action is not really setting anything to that.
Now the script
$(function(){
$("#name").change(function(){
var selected = $(this).find("option:selected").text();
$("#selectedItem").text(selected);
});
});
This will read the selected option's Text and set that on our span.
If you want this text in the HttpPost action, you can add a new property to your view model
public class studentmodel
{
public int id { get; set; }
public string name { get; set; }
public string SelectedText{ get; set; }
}
And keep a hidden field inside the form
#Html.HiddenFor(s=>s.SelectedText)
Now, set the value of this using javascript set the value of this hidden field.
$(function(){
$("#name").change(function(){
var selected = $(this).find("option:selected").text();
//var selected = $("#name option:selected").text(); // another option
$("#selectedItem").text(selected);
$("#SelectedText").val(selected);
});
});
Now when you submit the form, the value of the hidden field SelectedText will also be submitted.
Model add one viewmodel as below
public class studentmodel
{
public int id { get; set; }
public string name { get; set; }
}
public class SomeViewModel
{
public string studentname {get; set;}
public SelectList studentlist {get; set;}
}
Updated
public ActionResult Index()
{
SomeViewModel Model = new SomeViewModel();
var studentlist = new List<SelectListItem>();
studentlist.Add(new SelectListItem() { Value = "1", Text = "saurav" });
studentlist.Add(new SelectListItem() { Value = "2", Text = "Rj" });
studentlist.Add(new SelectListItem() { Value = "3", Text = "rahul" });
Model.studentlist = new SelectList(studentlist, nameof(SelectListItem.Value), nameof(SelectListItem.Text));
return View(Model);
}
[HttpPost]
public ActionResult Index(SomeViewModel s)
{
return View();
}
and change your view as below
Updated
#model somenamespace.SomeViewModel
#Html.DropDownListFor(m => m.studentname , Model.studentlist , "select student");

MVC Partial View throwing error on dropdownfor

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.

Resources