RadioButton Not Persisting on Submit When There's an Error - asp.net-mvc

I have two groups of Radio Buttons on a page:
Phone 1: [ ] Home | [x] Work | [ ] Cell
Phone 2: [ ] Home | [ ] Work | [x] Cell
When you see the page, I'm setting the defaults for Phone 1, "Work", and for Phone 2, "Cell". What is happening is that when a user submits and does not enter a required FirstName, AND selects Home (for Phone 1) and Home (Phone 2) - when the page refreshes, Phone 1 is "Home" and Phone 2 is "Cell".
How is this so? Phone 2 should be "Home" because that's what I selected before I got the error message. Any feedback is greatly appreciated!
Here's the view:
#using (Html.BeginForm("create", "PetSittingRequest"))
{
<label class="labelleft" style="width: 100px">First Name:</label>
<div class="formfield" style="width: 205px">
#Html.TextBoxFor(model => model.ClientDetails[0].NameFirst, new { style = "width: 195px" })
#Html.ValidationMessageFor(model => model.ClientDetails[0].NameFirst, null )
</div>
// Phone #1 START
<label class="labelleft" style="width: 100px">Phone 1:</label>
<div class="formfield" style="width: 60px">
#Html.TextBoxFor(model => model.Phones[0].PhoneNumber, new { style = "width: 195px" })
#Html.ValidationMessageFor(model => model.Phones[0].PhoneNumber, null)
</div>
<div class="formfield" style="width: 60px"></div>
<div class="formfield" style="width: 95px"></div>
<div class="formfield" style="width: 60px">
#Html.RadioButtonFor(model => model.Phones[0].Location, "Home", new { #class="radiobtn" } ) Home
</div>
<div class="formfield" style="width: 60px">
#Html.RadioButtonFor(model => model.Phones[0].Location, "Work", new { #class="radiobtn", #checked = true } ) Work
</div>
<div class="formfield" style="width: 60px">
#Html.RadioButtonFor(model => model.Phones[0].Location, "Cell", new { #class="radiobtn" } ) Cell
</div>
// Phone #2 START
<label class="labelleft" style="width: 100px">Phone 2:</label>
<div class="formfield" style="width: 60px">
#Html.TextBoxFor(model => model.Phones[1].PhoneNumber, new { style = "width: 195px" })
#Html.ValidationMessageFor(model => model.Phones[1].PhoneNumber, null)
</div>
<div class="formfield" style="width: 60px"></div>
<div class="formfield" style="width: 95px"></div>
<div class="formfield" style="width: 60px">
#Html.RadioButtonFor(model => model.Phones[1].Location, "Home", new { #class="radiobtn" } ) Home
</div>
<div class="formfield" style="width: 60px">
#Html.RadioButtonFor(model => model.Phones[1].Location, "Work", new { #class="radiobtn" } ) Work
</div>
<div class="formfield" style="width: 60px">
#Html.RadioButtonFor(model => model.Phones[1].Location, "Cell", new { #class="radiobtn", #checked = true } ) Cell
</div>
}
The controller that handles the post is this:
[HttpPost]
public ActionResult Create(ClientUser x)
{
try
{
return View("Index", x);
}
catch
{
return View();
}
}
Here are the models:
public class ClientUser
{
public List<ClientDetail> ClientDetails { get; set; }
public List<Phone> Phones { get; set; }
}
public class ClientDetail
{
[Required(ErrorMessage="This field is required.")]
public string NameFirst { get; set; }
}
public class Phone
{
[Required(ErrorMessage="This field is required.")]
public string PhoneNumber { get; set; }
[Required(ErrorMessage="This field is required.")]
public string Location { get; set; }
}

The problem is that at one side you are checking values of your radios using html attributes and on the other side you want your model value to set the same value. so what you want to do can be done by simply removing the #checked = true from your view for each radio buttons and if you need some specific value to be selected when first time form is rendered you can do something like
public ActionResult Create()
{
ClientUser clientUser = new ClientUser();
clientUser.ClientDetails = new List<ClientDetail> { new ClientDetail()};
clientUser.Phones = new List<Phone> { new Phone{Location = "Work"}, new Phone{Location = "Cell"} };
return View(clientUser);
}
this will set value of first radio group to "Work" and second group to "Cell" and will also change the values accordingly when you make changes on form and it is rendered back in case of an error. Moreover, why are you having list of clientDetails when you are showing just one user on the form. i would suggest changing your viewmodel to
public class ClientUser
{
public ClientDetail ClientDetails { get; set; }
public List<Phone> Phones { get; set; }
}

Related

MVC Dropdown list null on view on submit

I'm having issues with drop down lists on MVC. I've searched and searched but to no avail.
My ViewModel
public class IncidentFormViewModel
{
public Guid Guid { get; set; }
public Incident Incident { get; set; }
public Guid PersonInvolvedId { get; set; }
public IEnumerable<Person> People { get; set; }
}
My Controller
public ActionResult New()
{
var incidentFormVM = new IncidentFormViewModel
{
Incident = new Incident(),
People = unitofwork.Person.GetAll()
};
return View("IncidentForm", incidentFormVM);
}
and View(I've taken out useless information)
#using (Html.BeginForm("Save", "Incident"))
<div class="container">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
#Html.LabelFor(m => m.Incident.PersonInvolved)
#Html.DropDownListFor(m => m.PersonInvolvedId, new SelectList(Model.People, "Id", "FirstName"), new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Incident.PersonInvolved)
</div>
</div>
<br />
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
The thing is if i put a stop on the line below and put a watch on Model.People i can see the list of people against it.
#Html.DropDownListFor(m => m.PersonInvolvedId, new SelectList(Model.People, "Id", "FirstName"), new { #class = "form-control" })
What am i doing wrong?

Using a one model to populate the dropdown for the view on another model

I've been striking out on how to handle this situation. I have a model, the project model, and it has numerous items that need to be dropdowns for the user to change the selected item in question. I started out simple with the ProjectType value, which should have the selectable values populated form the ProjectTypes table. Here is the ViewModel:
public class ProjectViewModel
{
public APT_Projects Project { get; set; }
public System.Linq.IQueryable<APT_ProjectTypes> projecttypes { get; set; }
public APT_ClientTypes ClientTypes {get; set;}
}
Here is the controller:
public ActionResult Edit(int id = 0)
{
APT_Projects apt_projects = db.APT_Projects.Find(id);
if (apt_projects == null)
{
return HttpNotFound();
}
ProjectViewModel Project = new ProjectViewModel();
var apt_projecttypes = from a in db.APT_ProjectTypes
select a;
Project.Project = apt_projects;
Project.projecttypes = apt_projecttypes;
return View(Project);
}
and finally the view:
#model APTII_MVC.ViewModel.ProjectViewModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>APT_Projects</legend>
<div class="editor-label" style="float: left; width: 500px;" >
#Html.LabelFor(model => model.Project.Project_ID)
</div>
<div class="editor-field" style="float: left; width: 500px;" >
#Html.EditorFor(model => model.Project.Project_ID)
#Html.ValidationMessageFor(model => model.Project.Project_ID)
</div>
<div class="editor-label"">
#Html.LabelFor(model => model.Project.ProjectType_ID)
</div>
<div class="editor-field"">
#Html.DropDownListFor(model => model.Project.ProjectType_ID, Model.projecttypes)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
When I do it in this manner, .net doesn't like the Drowpdownlistfor, but I'm unclear how to use these values in a manner that the dropdownlistfor would accept. What is my mistake?
Edit: Relevent Error for the Dropdownlistfor.
'System.Web.Mvc.HtmlHelper<ViewModel.ProjectViewModel>' does not contain a definition for 'DropDownListFor' and the best extension method overload 'System.Web.Mvc.Html.SelectExtensions.DropDownListFor<TModel,TProperty>(System.Web.Mvc.HtmlHelper<TModel>, System.Linq.Expressions.Expression<System.Func<TModel,TProperty>>, System.Collections.Generic.IEnumerable<System.Web.Mvc.SelectListItem>)' has some invalid arguments c:\Visual Studio 2012\Projects\Test_MVC\Test_MVC\Views\Project\Edit.cshtml
you might need a List<SelectListItem> or SelectList().. so try converting your projecttypes object to
#Html.DropDownListFor(model => model.Project.ProjectType_ID, new SelectList(Model.projecttypes,"ID","Type")
or edit your viewmodel to
public SelectList projecttypes { get; set; }
and your controller code to
Project.projecttypes = new SelectList(db.APT_ProjectTypes,"ID","Type");
just guessing on your value/text field names

Two Ajax forms, one view model. Validation only works for one

I've got two forms on my page. My viewmodel looks like this:
public class HomeViewModel
{
[Required(ErrorMessage = "We kind of need an email address!")]
[EmailAddress(ErrorMessage = "This isn't an email address!")]
public string Email { get; set; }
public ContactForm ContactForm { get; set; }
}
ContactForm:
public class ContactForm
{
[Required(ErrorMessage = "We need your name, please!")]
public string Name { get; set; }
[Required(ErrorMessage = "We need your email, please!")]
[EmailAddress(ErrorMessage = "This isn't an email address!")]
public string EmailAddress { get; set; }
[Required(ErrorMessage = "Please elaborate a little!")]
public string Message { get; set; }
}
First form action:
public ActionResult FreeConsultSubmit(HomeViewModel model)
{
if (ModelState.IsValid)
{
//do stuff
}
return PartialView("_SubmitResult", false);
}
Second Action:
public ActionResult ContactSubmit(HomeViewModel model)
{
if (ModelState.IsValid)
{
//dostuff
}
return PartialView("_SubmitContactResult", false);
}
First Ajax Form
#using (Ajax.BeginForm("FreeConsultSubmit", new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "FreeConsultResults"
}))
{
<div id="FreeConsultResults">
<div class="row">
<div class="small-4 columns small-centered text-center splashEmail">
#Html.TextBoxFor(m => m.Email, new { #placeholder = "Please enter your email..." })
#Html.ValidationMessageFor(m => m.Email)
</div>
</div>
<div class="row">
<div class="small-5 columns small-centered text-center">
<input type="submit" class="hvr-border-fade splashCallToAction" value="Get Started" />
</div>
</div>
</div>
}
Second Ajax Form:
#using (Ajax.BeginForm("ContactSubmit", new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "ContactSubmitResults"
}))
{
<div id="ContactSubmitResults">
<div class="row">
<div class="small-12 columns small-centered">
#Html.TextBoxFor(m => m.ContactForm.Name, new { #placeholder = "Your Name" })
#Html.ValidationMessageFor(m => m.ContactForm.Name)
#Html.TextBoxFor(m => m.ContactForm.EmailAddress, new { #placeholder = "Your Email Address" })
#Html.ValidationMessageFor(m => m.ContactForm.EmailAddress)
#Html.TextAreaFor(m => m.ContactForm.Message, new { #placeholder = "Your Message", #class = "contactMessage" })
#Html.ValidationMessageFor(m => m.ContactForm.Message)
</div>
</div>
<div class="row">
<div class="small-12 columns small-centered text-center">
<a href="">
<input type="submit" class="hvr-border-fade sendMessageSmall" value="Send Message" />
</a>
</div>
</div>
</div>
}
I've got everything wired up fine, and client side validation works as it should. This may be overkill, but I also wanted to set up server side validation.
The issue is, when submitting the first form (just the email string), I check if the ModelState is valid, and it is. If you drill down into the ModelState, you see that only 1 property is being looked at.
If you submit the second form though (the ContactForm), the ModelState.IsValid returns false, and if you drill down, you see that it's looking at 4 properties (the 3 ContactForm properties, plus the string email). Since the email string is required, it fails.
I'm confused as to why it works for one, but not the other. I could just remove the server side validation, but I'd at least like to know why this is the case. I could also remove the error from the ModelState, but that doesn't seem elegant at all.
If you simply are trying to have two separate forms within one view, you're probably better off splitting the forms into separate "sub views" and child actions, and then using #Html.Action() to render them in place.
Here's an example:
Models
I'd remove the ContactForm model from HomeViewModel, and rename HomeViewModel to ConsultingForm (to match your naming convention for the contact model):
public class ConsultingForm
{
[Required(ErrorMessage = "We kind of need an email address!")]
[EmailAddress(ErrorMessage = "This isn't an email address!")]
public string Email { get; set; }
}
public class ContactForm
{
[Required(ErrorMessage = "We need your name, please!")]
public string Name { get; set; }
[Required(ErrorMessage = "We need your email, please!")]
[EmailAddress(ErrorMessage = "This isn't an email address!")]
public string EmailAddress { get; set; }
[Required(ErrorMessage = "Please elaborate a little!")]
public string Message { get; set; }
}
Controller
Add "child" actions, like those below:
public class HomeController : Controller
{
public ActionResult Home()
{
return View();
}
[ChildActionOnly, HttpGet]
public ActionResult ConsultingRequest()
{
var model = new ConsultingForm();
return View(model);
}
[ChildActionOnly, HttpGet]
public ActionResult ContactRequest()
{
var model = new ContactForm();
return View(model);
}
}
The ChildActionOnlyAttribute marks the action as a child action. From the MSDN:
A child action method renders inline HTML markup for part of a view
instead of rendering a whole view.
Views
Your first subview will be the same as you already have:
#using (Ajax.BeginForm("FreeConsultSubmit", new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "FreeConsultResults"
}))
{
<div id="FreeConsultResults">
<div class="row">
<div class="small-4 columns small-centered text-center splashEmail">
#Html.TextBoxFor(m => m.Email, new { #placeholder = "Please enter your email..." })
#Html.ValidationMessageFor(m => m.Email)
</div>
</div>
<div class="row">
<div class="small-5 columns small-centered text-center">
<input type="submit" class="hvr-border-fade splashCallToAction" value="Get Started" />
</div>
</div>
</div>
}
Your second subview simply needs to remove the extra "step" in the property bindings:
#using (Ajax.BeginForm("ContactSubmit", new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "ContactSubmitResults"
}))
{
<div id="ContactSubmitResults">
<div class="row">
<div class="small-12 columns small-centered">
#Html.TextBoxFor(m => m.Name, new { #placeholder = "Your Name" })
#Html.ValidationMessageFor(m => m.Name)
#Html.TextBoxFor(m => m.EmailAddress, new { #placeholder = "Your Email Address" })
#Html.ValidationMessageFor(m => m.EmailAddress)
#Html.TextAreaFor(m => m.Message, new { #placeholder = "Your Message", #class = "contactMessage" })
#Html.ValidationMessageFor(m => m.Message)
</div>
</div>
<div class="row">
<div class="small-12 columns small-centered text-center">
<a href="">
<input type="submit" class="hvr-border-fade sendMessageSmall" value="Send Message" />
</a>
</div>
</div>
</div>
}
The "wrapper", or parent view, will look something like:
<div class="whatever">
#Html.Action("ConsultingRequest", "Home")
#Html.Action("ContactRequest", "Home")
</div>
If you inspect the rendered HTML, you'll see that each form is properly bound to only its model's properties, so when you post each form, only those properties are model-bound and validated.

posting data from partial view on main view then submitting to controller

I have a MVC model as follows
public class ListSampleModel
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int SampleId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IList<PointOfContact> lstPoc { get; set; }
}
public class PointOfContact
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int PocID { get; set; }
public string EmailAddress { get; set; }
public string PhoneNumber { get; set; }
}
What I have done is, create "PointOfContact" as a partial view on a jquery dialog and on "save" button click it shows the data on the main view in labels (I will have multiple point of contacts), now on submit I want this data along with the property values of ListSampleData to be posted back to the controller.
The issue is, the data related to simple properties are returned back but the list is always null.
below is my View
#model MVCDataFlowSample.Models.ListSampleModel
#using (Html.BeginForm("Create", "ListSample", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>ListSampleModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div id="dialog1" class="ui-dialog" style="background-color:gray;"></div>
<div id="data">
</div>
<p>
<input type="button" value="Add More..." id="btnAdd" />
</p>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Javascript on Main View
<script type="text/javascript">
$(document).ready(function () {
$('#btnAdd').on('click', function () {
$('#dialog1').dialog({
autoOpen: true,
position: { my: "center", at: "center", of: window },
width: 1000,
resizable: false,
title: 'Add User Form',
modal: true,
open: function () {
$(this).load('#Url.Action("PocPartial", "ListSample")');
},
buttons: {
"Save User": function () {
addUserInfo();
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
}
});
return false;
});
function addUserInfo(email, phone) {
var text = "<div id='EmailAddress'>Email Address:" + $("#EAddress").val() + "</div><div id='PhoneNumber'>Phone Number:" + $("#PhNo").val() + "</div>";
$("#data").append(text);
}
});
</script>
Partial View
#model MVCDataFlowSample.Models.PointOfContact
<div>
#Html.Label("EmailAddress:")
<div>
#Html.TextBoxFor(x => x.EmailAddress, new { id = "EAddress" })
</div>
#Html.Label("PhoneNumber:")
<div>
#Html.TextBoxFor(x => x.PhoneNumber, new { id = "PhNo" })
</div>
</div>
any help will be appreciated.
The contents of DIV elements are not submitted as form data. If you'd like that data to be submitted, add it to the DOM as hidden INPUT elements in addition to your DIVs. You'll also need to format their names correctly so that MVC knows how to bind them. See this article for how complex objects are bound in MVC.
I posted partial view data to the main page's post action You can modify the idea to any of your suits
Partial View
<select name="Country">
<option>Indian</option>
<option>Africa</option>
</select>
<select name="State">
<option>Kerala</option>
<option>TamilNadu</option>
</select>
<select name="City">
<option>Thrissur</option>
<option>Palakkad</option>
</select>
Index Page
#{
ViewBag.Title = "IndexTestPost";
}
<h2>IndexTestPost</h2>
#using(Html.BeginForm()){
#Html.Partial("~/Views/_PartialPagePostCountry.cshtml");
<input type="submit" />
}
Class To Catch Post Data
public class CountryCityState
{
public string Country { get; set; }
public string State { get; set; }
public string City { get; set; }
}
Controller
public class TestPostPartialController : Controller
{
// GET: TestPostPartial
public ActionResult IndexTestPost()
{
return View();
}
[HttpPost]
public ActionResult IndexTestPost(CountryCityState CtnCtySta)
{
return View();
}
}

mvc getting and sending data from dropdown and datetimepicker

hello everyone I have a question. I have a form which consist of dropdown textbox and datetimepicker. I can fill my dropdown from my model but I cannot post the data to the database. Here are my codes
My Controller codes this is where the data selected and shown in view
public ActionResult orderProduct()
{
Repository<OrderProduct> _ro = new Repository<OrderProduct>();
IEnumerable<OrderProduct> _orderProduct = _ro.All().OrderByDescending(o => o.id);
return View(_orderProduct);
}
I am filling the dropdownlist from database
public ActionResult addOrderProduct()
{
/*
Repository<Workshop> _rw = new Repository<Workshop>();
IEnumerable<Workshop> _workshop = _rw.All().OrderByDescending(o => o.id);
IEnumerable<SelectListItem> _selectList = from w in _workshop
select new SelectListItem {
Text = w.name,
Value = w.id.ToString()
};
*/
Repository<Workshop> _rw = new Repository<Workshop>();
IEnumerable<SelectListItem> _workshopSelectListItem = _rw.All().AsEnumerable().Select(s =>
new SelectListItem {
Text = s.name, Value=s.id.ToString()
});
ViewData["dropdown"] = _workshopSelectListItem;
return View();
}
here I am trying to post my data to the database. I cannot select data from dropdown and datetimepicker also I cannot post this data by writing manually.
public ActionResult orderProductAdd(int adet, float cmt)
{
Repository<OrderProduct> _rp = new Repository<OrderProduct>();
OrderProduct _orderProduct = new OrderProduct { workshopId = 1, orderId = 1, value = adet, shipDate = new DateTime(2005, 02, 01), cmt = cmt };
return RedirectToAction("orderProduct");
}
this is my model
[Table("OrderProduct")]
public class OrderProduct
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
public int orderId { get; set; }
[ForeignKey("orderId")]
public virtual Order order { get; set; }
public int workshopId { get; set; }
[ForeignKey("workshopId")]
public virtual Workshop workshop { get; set; }
public int value { get; set; }
public float cmt { get; set; }
public DateTime shipDate { get; set; }
/*
[id]
,[orderId]
,[workshopId]
,[value]
,[cmt]
,[shipDate]
*/
}
and also this is my view "addOrderProduct"
<form action="/Order/orderProductAdd" class="form-horizontal">
<div class="control-group">
<label class="control-label">Atölye Seçiniz</label>
<div class="controls">
#Html.DropDownList("dropdown",(IEnumerable<SelectListItem>)ViewData["dropdown"],"secim yapınız", new { #class = "span6 chosen" })
#*<select class="span6 chosen" data-placeholder="Choose a Category" tabindex="1">
<option value=""></option>
<option value="Category 1">A1</option>
<option value="Category 2">A2</option>
<option value="Category 3">A3</option>
<option value="Category 4">A4</option>
</select>*#
</div>
</div>
<div class="control-group">
<label class="control-label">Adet Giriniz</label>
<div class="controls">
<input type="text" class="span6 " name="adet" />
<span class="help-inline">Sadece sayı giriniz</span>
</div>
</div>
<div class="control-group last">
<label class="control-label">İhracat Tarihi</label>
<div class="controls">
<div id="ui_date_picker_inline"></div>
</div>
</div>
<div class="control-group">
<label class="control-label">Cmt</label>
<div class="controls">
<input type="text" class="span6 " name="cmt" />
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-success">Onayla</button>
#*<button type="button" class="btn">Cancel</button>*#
</div>
</form>
How can I solve this ? Thank you.
The first argument in the DDL (below) is the assigned parameter being passed back to the server. When you call the action you're not passing the parameter dropdown. You're only calling int adet, float cmt but not a parameter called dropdown
#Html.DropDownList("dropdown",(IEnumerable<SelectListItem>)ViewData["dropdown"],
"secim yapınız", new { #class = "span6 chosen" })
So update your code to something like the one below:
public ActionResult orderProductAdd(int adet, float cmt, string dropdown){
// DO SOMETHING HERE
}
I can't see the input control which is being constructed for the DATETIME part of your query, however it will be similar to the above. Ensure the name of the INPUT matches the parameters being passed back to the server.

Resources