I am very new to MVC5 and JQuery and I trying to create a cascading drop down. When the user selects a Practice from the drop down I am trying to get the Opticians that work in that Practice to populate.
Optician Model:
public class Optician
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid OpticianId { get; set; }
[ForeignKey("User")]
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
public IEnumerable<SelectListItem> UserList { get; set; }
[ForeignKey("Practice")]
public Guid PracticeId { get; set; }
public virtual Practice Practice { get; set; }
public IEnumerable<SelectListItem> PracticeList { get; set; }
public virtual ICollection<ApplicationUser> Users { get; set; }
public virtual ICollection<Practice> Practices { get; set; }
}
Practice Model:
public class Practice
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Display(Name = "Practice")]
public Guid PracticeId { get; set; }
[Display(Name = "Practice Name")]
public string PracticeName { get; set; }
public virtual ICollection<Optician> Opticians { get; set; }
public virtual ICollection<Booking> Bookings { get; set; }
}
Application User Model:
public class ApplicationUser : IdentityUser
{
[Display(Name = "Title")]
public string Title { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
}
Controller :
public ActionResult TestDropDown()
{
var PracticeListItems = (from d in db.Practices
select d.PracticeName).ToList();
SelectList Practice = new SelectList(PracticeListItems);
ViewData["Practice"] = Practice;
return View();
}
public JsonResult Opticians(Guid? Id)
{
var OpticianList = (from d in db.Opticans
where d.PracticeId == Id
select d.User.FirstName).ToList();
return Json(OpticianList);
}
The View:
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script>
$(document).ready(function () {
$("#Optician").prop("disabled", true);
$("#Practice").change(function () {
if ($("#Practice").val() != "Select") {
var PracticeOptions = {};
PracticeOptions.url = "/Bookings1/Opticians";
PracticeOptions.type = "POST";
PracticeOptions.data = JSON.stringify({ Practice: $("#Practice").val() });
PracticeOptions.datatype = "json";
PracticeOptions.contentType = "application/json";
PracticeOptions.success = function (OpticianList) {
$("#Optician").empty();
for (var i = 0; i < OpticianList.length; i++) {
$("#Optician").append("<option>" + StatesList[i] + "</option>");
}
$("#Optician").prop("disabled", false);
};
PracticeOptions.error = function () { alert("Error in getting Practices"); };
$.ajax(PracticeOptions);
}
else {
$("#Optician").empty();
$("#Optician").prop("disabled", true);
}
});
});
#using (Html.BeginForm("TestDropDown", "Bookings1", FormMethod.Post))
{
#Html.AntiForgeryToken()
<h4>Select Practcie & Opticians</h4>
<hr />
#Html.ValidationSummary()
<div class="form-group">
#Html.Label("Select Practice :", new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownList("Practice", ViewData["Practices"] as SelectList, new { #class = "form-control" })
</div>
</div><br />
<div class="form-group">
#Html.Label("Select Optician :", new { #class = "col-md-2 control-label" })
<div class="col-md-10">
<select id="Optician"></select>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Submit" />
</div>
</div>
}
However, when I run the application the Practice Name populates but the Optician First Name does not. There are no errors and I am unsure of where I am going wrong. Any help would be greatly appreciated.
Seems like you have a few issues with your code.. Starting with your SelectList.
When you define your select list it helps if you tell it what your Value and Text properties are..
public ActionResult TestDropDown()
{
var practices = new SelectList(db.Practices, "PracticeId", "PracticeName");
ViewData["Practices"] = practices;
return View();
}
Then you should probably return more information in your Opticians json result
[HttpPost]
public JsonResult Opticians(Guid? Id)
{
var opticianList = db.Opticians.Where(a => a.PracticeId == Id).Select(a => a.User).ToList();
return Json(opticianList);
}
In your javascript once you get the names sorted out out you can reference the property FirstName of the result.
$(document).ready(function () {
$("#Optician").prop("disabled", true);
$("#Practice").change(function () {
$.ajax({
url = "#Url.Action("Opticians","Bookings1")",
type = "POST",
data = {Id : $(this).val() }
}).done(function(OpticianList){
$("#Optician").empty();
for (var i = 0; i < OpticianList.length; i++) {
$("#Optician").append("<option>" + OpticianList[i].FirstName + "</option>");
}
$("#Optician").prop("disabled", false);
});
});
});
I'm not sure why you were passing paramater Practice to an action that took a parameter Id but it should be fixed in the code above.
Related
I'm having trouble understanding how to retrieve data from my Device table in my database to a CheckBoxList.
I believe I have the Models, ViewModel and Database setup properly but I'm just not sure what to do next. For now, I would simple like to learn how to retrieve the data from my table to a CheckBoxList.
Customer Model
public class Customer
{
public int CustId { get; set; }
public string CustDisplayName { get; set; }
public string CustFirstName { get; set; }
public string CustLastName { get; set; }
public string CustCompanyName { get; set; }
public string CustAddress { get; set; }
public string CustPhoneNumber { get; set; }
public string CustMobileNumber { get; set; }
public string CustEmailAddress { get; set; }
public int StId { get; set; }
public State State { get; set; }
}
State Model
public class State
{
public int StId { get; set; }
public string StAbbr { get; set; }
public List<Customer> Customers { get; set; }
}
Device Model
public class Device
{
public int DevId { get; set; }
public string DevType { get; set; }
public bool isChecked { get; set; }
}
CustomerDevice Model
public class CustomerDevice
{
public int CustId { get; set; }
public int DevId { get; set; }
public Customer Customer { get; set; }
public Device Device { get; set; }
}
CustomerViewModel
public class CustomerFormViewModel
{
public int CustId { get; set; }
[Required(ErrorMessage = "Enter Display Name")]
[Display(Name = "Display Name")]
[StringLength(100)]
public string CustDisplayName { get; set; }
[Display(Name = "First Name")]
[StringLength(50)]
public string CustFirstName { get; set; }
[Display(Name = "Last Name")]
[StringLength(50)]
public string CustLastName { get; set; }
[Display(Name = "Company Name")]
[StringLength(50)]
public string CustCompanyName { get; set; }
[Display(Name = "Phone Number")]
[DataType(DataType.PhoneNumber)]
[StringLength(12)]
public string CustPhoneNumber { get; set; }
[Display(Name = "Mobile Number")]
[DataType(DataType.PhoneNumber)]
[StringLength(12)]
public string CustMobileNumber { get; set; }
[Display(Name = "Email Address")]
[DataType(DataType.EmailAddress)]
[StringLength(320)]
public string CustEmailAddress { get; set; }
[Required(ErrorMessage = "Enter Address")]
[Display(Name = "Address")]
[StringLength(100)]
public string CustAddress { get; set; }
[Required(ErrorMessage = "Select State")]
[Display(Name = "State")]
public int StId { get; set; }
public IEnumerable<State> States { get; set; }
}
CustomerController
public class CustomerController : Controller
{
private CoreWebAppContext _context;
public CustomerController(CoreWebAppContext context)
{
_context = context;
}
// GET: /<controller>/
public IActionResult Index()
{
return View(_context.Customers.ToList());
}
public ActionResult Create()
{
var states = _context.States.ToList();
var viewModel = new CustomerFormViewModel
{
States = states
};
return View(viewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CustomerFormViewModel vm)
{
if (ModelState.IsValid)
{
var customer = new Customer();
{
customer.CustDisplayName = vm.CustDisplayName;
customer.CustFirstName = vm.CustFirstName;
customer.CustLastName = vm.CustLastName;
customer.CustCompanyName = vm.CustCompanyName;
customer.CustAddress = vm.CustAddress;
customer.CustPhoneNumber = vm.CustPhoneNumber;
customer.CustMobileNumber = vm.CustMobileNumber;
customer.CustEmailAddress = vm.CustEmailAddress;
customer.StId = vm.StId;
}
_context.Customers.Add(customer);
_context.SaveChanges();
return RedirectToAction("Index");
}
else
{
vm.States = _context.States.ToList();
return View(vm);
}
}
public ActionResult Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var customervm = new CustomerFormViewModel();
{
Customer customer = _context.Customers.SingleOrDefault(c => c.CustId == id);
if (customer == null)
{
return NotFound();
}
customervm.CustId = customer.CustId;
customervm.CustDisplayName = customer.CustDisplayName;
customervm.CustFirstName = customer.CustFirstName;
customervm.CustLastName = customer.CustLastName;
customervm.CustCompanyName = customer.CustCompanyName;
customervm.CustAddress = customer.CustAddress;
customervm.CustPhoneNumber = customer.CustPhoneNumber;
customervm.CustMobileNumber = customer.CustMobileNumber;
customervm.CustEmailAddress = customer.CustEmailAddress;
// Retrieve list of States
var states = _context.States.ToList();
customervm.States = states;
// Set the selected state
customervm.StId = customer.StId;
}
return View(customervm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(CustomerFormViewModel vmEdit)
{
if (ModelState.IsValid)
{
Customer customer = _context.Customers.SingleOrDefault(c => c.CustId == vmEdit.CustId);
if (customer == null)
{
return NotFound();
}
customer.CustDisplayName = vmEdit.CustDisplayName;
customer.CustFirstName = vmEdit.CustFirstName;
customer.CustLastName = vmEdit.CustLastName;
customer.CustCompanyName = vmEdit.CustCompanyName;
customer.CustAddress = vmEdit.CustAddress;
customer.CustPhoneNumber = vmEdit.CustPhoneNumber;
customer.CustMobileNumber = vmEdit.CustMobileNumber;
customer.CustEmailAddress = vmEdit.CustEmailAddress;
customer.StId = vmEdit.StId;
_context.Entry(customer).State = EntityState.Modified;
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(vmEdit);
}
}
Create View
<div class="form-group">
#Html.LabelFor(c => c.CustDisplayName)
#Html.TextBoxFor(c => c.CustDisplayName, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustDisplayName)
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustFirstName)
#Html.TextBoxFor(c => c.CustFirstName, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustLastName)
#Html.TextBoxFor(c => c.CustLastName, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustCompanyName)
#Html.TextBoxFor(c => c.CustCompanyName, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustAddress)
#Html.TextBoxFor(c => c.CustAddress, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustAddress)
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustPhoneNumber)
#Html.TextBoxFor(c => c.CustPhoneNumber, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustPhoneNumber)
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustMobileNumber)
#Html.TextBoxFor(c => c.CustMobileNumber, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustMobileNumber)
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustEmailAddress)
#Html.TextBoxFor(c => c.CustEmailAddress, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustEmailAddress)
</div>
<div class="form-group">
#Html.LabelFor(s => s.StId)
#Html.DropDownListFor(s => s.StId, new SelectList(Model.States, "StId", "StAbbr"), "", new { #class = "form-control" })
#Html.ValidationMessageFor(s => s.StId)
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
Make another ViewModel class called IndexViewModel and put this on it:
public class IndexViewModel
{
public List<Customer> Customers { get; set; }
public List<Device> Devices { get; set; }
}
Here is your controller Action. Return the new IndexViewModel instead:
// GET: /<controller>/
public IActionResult Index()
{
return View(_context.Customers.ToList());
}
to
// GET: /<controller>/
public IActionResult Index()
{
var model = new IndexViewModel();
model.Customers = _context.Customers.ToList();
model.Devices = _context.Devices.ToList();
return View(model);
}
In your view, simply iterate the Device list:
#{
for(int i = 0; i < Model.Devices.Count(); i++)
{
var checkboxAttributes = Model.Devices[i].isChecked == true ?
(object) new { #class = "checkbox", #checked = "checked" } :
(object) new { #class = "checkbox" };
#Html.CheckBoxFor(model => model.Devices[i].DevType, checkboxAttributes)
#Html.LabelFor(model => model.Devices[i].DevType, new { #class = "label" })
}
}
Update 1
I'm sorry about the previous one but this is the correct version: It uses bootstrap style for the checkbox:
#{
for (int i = 0; i < Model.Devices.Count(); i++)
{
<div class="checkbox">
<label>
#Html.HiddenFor(model => model.Devices[i].DevId)
#Html.CheckBoxFor(model => model.Devices[i].isChecked)
#Html.DisplayFor(model => model.Devices[i].DevType)
#Html.HiddenFor(model => model.Devices[i].DevType)
</label>
</div>
}
}
You can use something like this, so you can reuse it for different models.
CheckboxViewModel:
public class CheckboxViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool Checked { get; set; }
}
Extension method:
public static IEnumerable<CheckboxViewModel> CreateCheckboxList<T>(this List<T> entities, Func<T, object> value, Func<T, object> text, Func<T, bool> isChecked)
{
return entities.Select(x => new CheckboxViewModel
{
Id = (int)value(x),
Name = text(x).ToString(),
Checked = isChecked(x)
});
}
Using example:
result = devices.CreateCheckboxList(x => x.Id, x => x.Name, x => selectedDevices.Contains(x.Id)).ToList();
#for (var deviceIndex = 0; deviceIndex < Model.Devices.Count(); deviceIndex ++)
{
<div class="form-group">
<div class="checkbox checkbox-primary">
#Html.HiddenFor(model => model.Devices[deviceIndex ].Id)
#Html.CheckBoxFor(model => model.Devices[deviceIndex ].Checked)
#Html.LabelFor(model => model.Devices[deviceIndex ].Checked, Model.Devices[deviceIndex ].Name)
</div>
</div>
}
I'm getting a validation error message on my DropDownList within my Create Action if I click the submit button without selecting a value from the DropDownList.
The validation error that I'm getting is The value "" is invalid. I would like the validation error message to say State is required! instead.
I added the required validation attribute to the StId property on the ViewModel but that did not resolve the issue.
Customer Model
public class Customer
{
public int CustId { get; set; }
public string CustFirstName { get; set; }
public string CustLastName { get; set; }
public int StId { get; set; }
public State State { get; set; }
}
State Model
public class State
{
public int StId { get; set; }
public string StAbbr { get; set; }
public List<Customer> Customers { get; set; }
}
CustomerFormViewModel
public class CustomerFormViewModel
{
public int CustId { get; set; }
[Required(ErrorMessage = "First Name is required!")]
[Display(Name = "First Name")]
public string CustFirstName { get; set; }
[Required(ErrorMessage = "Last Name is required!")]
[Display(Name = "Last Name")]
public string CustLastName { get; set; }
[Required(ErrorMessage = "State is required!")]
[Display(Name = "State")]
public int StId { get; set; }
public IEnumerable<State> States { get; set; }
}
CustomerController
public class CustomerController : Controller
{
private OneClickAwayDbContext _context;
public CustomerController(OneClickAwayDbContext context)
{
_context = context;
}
public ActionResult Index()
{
return View(_context.Customers.ToList());
}
public ActionResult Create()
{
var states = _context.States.ToList();
var viewModel = new CustomerFormViewModel
{
States = states
};
return View(viewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CustomerFormViewModel vm)
{
if (ModelState.IsValid)
{
var customer = new Customer();
{
customer.CustFirstName = vm.CustFirstName;
customer.CustLastName = vm.CustLastName;
customer.StId = vm.StId;
}
_context.Customers.Add(customer);
_context.SaveChanges();
return RedirectToAction("Index");
}
else
{
var stateViewModel = new CustomerFormViewModel
{
States = _context.States.ToList()
};
return View("Create", stateViewModel);
}
}
}
Create.chtml
#using (Html.BeginForm("Create", "Customer"))
{
<div class="form-group">
#Html.LabelFor(c => c.CustFirstName)
#Html.TextBoxFor(c => c.CustFirstName, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustFirstName)
</div>
<div class="form-group">
#Html.LabelFor(c => c.CustLastName)
#Html.TextBoxFor(c => c.CustLastName, new { #class = "form-control" })
#Html.ValidationMessageFor(c => c.CustLastName)
</div>
<div class="form-group">
#Html.LabelFor(s => s.StId)
#Html.DropDownListFor(s => s.StId, new SelectList(Model.States, "StId", "StAbbr"), "", new { #class="form-control"})
#Html.ValidationMessageFor(s => s.StId)
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
}
Please include jquery.validate.js and jquery.validate.unobtrusive.js in your cshtml file
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
add this line in web.config
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
include following jquery file in your layout page.
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
Using this your submit button click event is not going to your [HttpPost] Action of your view if any validation are required.
I have a Razor page that displays a list of meetings. Each meeting has a id which is an attribute of a link assigned to each meeting which when clicked loads another Razor View showing the meeting details. This view calls a childAction which loads a partial page, displaying dropdown containing all available attendees and a <div> which will show a form if new visitors need to be created. The URL of the details page looks like
http://localhost:53533/Meetings/AddVisitors/18
I can select a visitor from the dropdown list and I have a working method that create a new record linking the visitor to the meeting. The methods returns the view having added the record, but the details are not shown in the refreshed table and the meeting id has gone from the page URL.
The method to show the page is:
public ActionResult AddVisitors(int? id)
{
var meetings = db.Meetings.Include("Host").Include("VisitorsMeetings").Where(x => x.id == id).FirstOrDefault();
return View(meetings);
}
The method that creates the visitor/meeting record is:
[HttpPost]
public ActionResult AddVisitors(VisitorList model)
{
VisitorMeeting newVisitorMeeting = new VisitorMeeting
{
MeetingId = model.meetingId,
VisitorId = model.SelectedId,
Arrived = false,
Departed = false,
BadgePrinted = false
};
db.VisitorMeetings.Add(newVisitorMeeting);
db.SaveChanges();
var meetings = db.Meetings.Include("Host").Include("VisitorsMeetings").Where(x => x.id == model.meetingId).FirstOrDefault();
return AddVisitors(model.meetingId);
}
The view is:
#model VisitorManager.Models.Meeting
....
<div>
<h4>Meeting</h4>
<dl class="dl-horizontal">
<dt>#Html.DisplayNameFor(model => model.Host.Name)</dt>
<dd>#Html.DisplayFor(model => model.Host.Name)</dd>
<dt>#Html.DisplayNameFor(model => model.StartTime)</dt>
<dd>#Html.DisplayFor(model => model.StartTime)</dd>
... // more properties of Meeting
</dl>
</div>
<h4>Visitor List</h4>
<div>
<table class="table">
<tr>
<th>Visitor Name</th>
<th>Company</th>
...
<th></th>
</tr>
#foreach (var item in Model.VisitorsMeetings)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.Visitor.VisitorName</td>
<td>#Html.DisplayFor(modelItem => item.Visitor.Company)</td>
<td>#Html.DisplayFor(modelItem => item.Arrived)</td>
....
<td>#Html.ActionLink("Delete", "Delete", new { id = item.VisitorId })</td>
</tr>
}
</table>
</div>
// Add partial view to show drop down of all visitors
#Html.Action("VisitorList", "Meetings")
#section Scripts{
<script type="text/javascript">
var dialog = $('#dialog-mask');
$('#addVisitor').click(
function () {
$('#VisitorModal').load('#Url.Action("Add", "Meetings")');
//$('#VisitorModal').find('form')[0].reset();
//dialog.find('form')[0].reset();
dialog.show();
}
);
$('#cancel').on('click', function () {
dialog.hide();
return false;
});
$('#VisitorModal').on('submit', '#visitorform', function () {
var data = $(this).serialize();
var url = '#Url.Action("AddVisitors", "Meetings")';
var text = $('#title').val() + ' ' + $('#firstname').val() + ' ' + $('#surname').val() + ' (' + $('#company').val() + ')'; // a value from the form that you want as the option text
$.post(url, data, function (response) {
if (response) {
$('#VisitorID').append($('<option></option>').val(response).text(text)).val(response);
} else {
dialog.hide();
// Oops
}
}).fail(function () {
// Oops
dialog.hide();
});
// ... close the modal
//$('#VisitorModal').hide();
//$('#VisitorModal').find('form')[0].reset();
dialog.hide();
return false; // cancel the default submit
});
</script>
}
The PartialView is:
#using VisitorManager.Models
#model VisitorList
#{
Layout = null;
}
#using (Html.BeginForm("AddVisitors", "Meetings"))
{
#Html.AntiForgeryToken()
<hr />
<div class="form-horizontal">
<h4>Add A Visitor</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.Label("Visitor Name", htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-4">
#Html.DropDownListFor(m => m.SelectedId, Model.Data, "- Please select -", htmlAttributes: new { #class = "form-control", #id="VisitorID" })
</div>
<button type="button" id="addVisitor" class="btn btn-success">Create new Visitor</button>
</div>
#Html.HiddenFor(m=>m.meetingId)
<div class="form-group">
<div class="col-md-offset-4 col-md-8">
<input type="submit" value="Add Visitor" class="btn btn-default" />
</div>
</div>
</div>
}
<div id="dialog-mask">
<div id="dialog" style="width:500px; height:auto;">
<div id="VisitorModal"></div>
</div>
</div>
VisitorList Action:
[ChildActionOnly]
public ActionResult VisitorList()
{
var dropDownData = db.Visitors.OrderBy(z => z.Company).ThenBy(y=>y.LastName).ThenBy(x=>x.FirstName)
.Select(d => new SelectListItem
{
Text = d.Title + " " + d.FirstName + " " + d.LastName + " (" + d.Company + ")",
Value = d.id.ToString()
});
var model = new VisitorList
{
Data = dropDownData,
meetingId = 18
};
return PartialView(model);
}
VisitorList viewmodel:
public class VisitorList
{
public IEnumerable<SelectListItem> Data { get; set; }
public int SelectedId { get; set; }
public int meetingId { get; set; }
}
Meeting model:
public class Meeting
{
public int id { get; set; }
[Display(Name="Start Time", Prompt = "Please supply a start date and time.")]
[Required(ErrorMessage = "Please supply a start date and time.")]
[DataType(DataType.DateTime)]
public DateTime StartTime { get; set; }
.... // more properties
[Required]
[ForeignKey("Host")]
[Display(Name="Meeting Host")]
public int HostId { get; set; }
[Display(Name="Meeting Host")]
public virtual Host Host { get; set; }
public ICollection<VisitorMeeting> VisitorsMeetings { get; set; }
}
Visitor Model:
public class Visitor
{
public int id { get; set; }
[Display(Name="Visitor Title")]
[Required]
public string Title { get; set; }
[Display(Name="Visitor Firstname")]
[Required]
public string FirstName { get; set; }
[Display(Name="Visitor Lastname")]
[Required]
public string LastName { get; set; }
[Display(Name="Company Name")]
[Required]
public string Company { get; set; }
[NotMapped]
[Display(Name="Visitor Name")]
public string VisitorName
{
get
{
return Title + " " + FirstName + " " + LastName;
}
}
public ICollection<VisitorMeeting> VisitorsMeetings { get; set; }
}
VisitorMeeting Model:
public class VisitorMeeting
{
public int Id { get; set; }
[Display(Name="Visitor Arrived")]
[Required]
public bool Arrived { get; set; }
.... // more properties
[Required]
[ForeignKey("Meeting")]
public int MeetingId { get; set; }
public virtual Meeting Meeting{ get; set; }
[Required]
[ForeignKey("Visitor")]
public int VisitorId { get; set; }
public virtual Visitor Visitor { get; set; }
}
Can anyone tell me How I keep the meeting ID in the AddVisitors URL and why the complete added visitor row isn't correctly showing in the list of visitors displayed in the partial view called by the child action?
There is several options to do so.
I advise you to use post-redirect-get pattern as it will safe for user to refresh page any time:
[HttpPost]
public ActionResult AddVisitors(VisitorList model)
{
// ...
return this.Redirect("AddVisitors", new { id = model.meetingId});
}
Another way is to generate appropriate post url. Look like you use default route mapping, so valid url should be generated:
#using (Html.BeginForm("AddVisitors", "Meetings", new { id = Model.meetingId }))
I have a View:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="input-group">
<div class="input-group-addon">
#Html.Label("Employee number", new { #class = "control-label" })
</div>
<div class="a">
#Html.TextBoxFor(model => model.EmployeeNo, new {#class="form-control" })
#Html.ValidationMessageFor(model => model.EmployeeNo)
</div>
</div>
/*
* other fields
*/
}
and Controller:
[HttpPost]
public ActionResult Edit([Bind(Include="Id,EmployeeNo,Name,Surname,ContactInfo,RoleId")] User user)
{
ValidateRequestHeader(Request);
if (ModelState.IsValid)
{
unitOfWork.userRepository.Update(user);
unitOfWork.Save();
return Json(new { ok = true, newurl = Url.Action("Index") });
}
//ModelState.AddModelError("", "Niepoprawne dane");
ViewBag.RoleId = new SelectList(unitOfWork.roleRepository.Get(), "Id", "RoleName", user.RoleId);
return PartialView(user);
}
and model:
public partial class User
{
public User()
{
this.DeviceUsages = new HashSet<DeviceUsage>();
}
public int Id { get; set; }
[Required(ErrorMessage="Brak numeru pracownika")]
public string EmployeeNo { get; set; }
[Required(ErrorMessage = "Brak imienia")]
public string Name { get; set; }
[Required(ErrorMessage = "Brak nazwiska")]
public string Surname { get; set; }
[Required(ErrorMessage = "Brak Adresu email")]
public string ContactInfo { get; set; }
public int RoleId { get; set; }
}
Data annotations are working. If I leave eg. Name empty ModelState is not Valid in controler. But validation messages are not shown. If I uncomment this line:
ModelState.AddModelError("", "Niepoprawne dane"); this will be the only Model error shown in the View.
Where is a mistake in my code?
It's because you are using #Html.ValidationSummary(true) means excludePropertyErrors = true
I would like to know if it is even possible to combine jQuery with a #Html.DropDownListFor in a strongly typed view, as I am beginning to suspect that either it isn't, or my approach to this problem is flawed.
Model:
public class NewUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public string ConfirmEmail { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
public SelectListItem DOBDay { get; set; }
public SelectListItem DOBMonth { get; set; }
public SelectListItem DOBYear { get; set; }
public string Gender { get; set; }
}
View:
#model test.Models.NewUser
#using (Ajax.BeginForm("RegisterUser", "Register", new AjaxOptions { OnSuccess = "" }))
{
<div>
#Html.TextBoxFor(m => Model.FirstName, new { #class = "big_i", #watermark = "First name" })
#Html.TextBoxFor(m => Model.LastName, new { #class = "big_i", #watermark = "Last name" })
</div>
<div>
#Html.TextBoxFor(m => Model.EmailAddress, new { #class = "big_i long_i", #watermark = "E-mail address" })
</div>
<div>
#Html.TextBoxFor(m => Model.ConfirmEmail, new { #class = "big_i long_i", #watermark = "Confirm e-mail address" })
</div>
<div>
#Html.PasswordFor(m => Model.Password, new { #class = "big_i long_i", #watermark = "Password" })
</div>
<div>
#Html.PasswordFor(m => Model.ConfirmPassword, new { #class = "big_i long_i", #watermark = "Confirm password" })
</div>
<div>
<fieldset>
<h2>
Date of birth</h2>
<div id="reg_date_control" class="date_control">
#Html.DropDownListFor(m => Model.DOBDay, Enumerable.Empty<SelectListItem>(), "Day: ", new { #class = "dc-days big_i" })
#Html.DropDownListFor(m => Model.DOBMonth, Enumerable.Empty<SelectListItem>(), "Month: ", new { #class = "dc-months big_i" })
#Html.DropDownListFor(m => Model.DOBYear, Enumerable.Empty<SelectListItem>(), "Year: ", new { #class = "dc-years big_i" })
</div>
</fieldset>
</div>
}
Controller action for form submit:
[HttpPost]
public ActionResult RegisterUser(Models.NewUser model)
{
string firstName = model.FirstName;
string lastName = model.LastName;
string email = model.EmailAddress;
string confirm_email = model.ConfirmEmail;
string password = model.Password;
string confirm_password = model.ConfirmPassword;
string dob_month = model.DOBMonth.Value; // an error is raised here
return View();
}
I am trying to initially bind the #Html.DropDownListFor with an empty list, which the jQuery will then populate. I won't paste the jQuery code here, it is basically populating each DOB drop down with the valid number of days in a selected month.
The lists populate fine. However, DOBDay, DOBMonth, and DOBYear are always null. I expect that using Enumerable.Empty() is my problem, but having said that, I have tried populating the dropdowns like so:
#model gs_mvc.Models.NewUser
#{
string[] months = new[]{"January", "February", "March", "April", "etc"};
var items = new List<SelectListItem>();
for (int i = 0; i < months.Length; i++) {
items.Add(new SelectListItem { Value = i.ToString(), Text = months[i] });
}
}
...
#Html.DropDownListFor(m => Model.DOBMonth, items, "Month: ", new { #class = "big_i" })
which also gives a null value.
At this point, I believe that my best bet would be to move the functionality of my jQuery script to C#, and do an AJAX call each time the dropdowns are changed. However, I wanted to check here first that I'm not missing something blindingly obvious that would allow me to do what I'm trying.
I think your problem is that the values on the model for month, day, and year should probably be int not SelectListItem. SelectListItem is used to build the options, since it has both the Text and Value properties, but what you want to and will receive back are just the values - not Text/Value pairs. Of course, you probably want to make them nullable so that you're sure that you're receiving values from the POST rather than just having them default to zero.
public class NewUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public string ConfirmEmail { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
public int? DOBDay { get; set; }
public int? DOBMonth { get; set; }
public int? DOBYear { get; set; }
public string Gender { get; set; }
}