MVC Model Binding for EditorFor - asp.net-mvc

I have three class types Search, BaseSearch and TextSearch of the following relation. Search is composed of a List<BaseSearch> and TextSearch inherits from BaseSearch, BaseSearch is abstract.
Now I would like to use Html helper to draw a list of TextSearch, EditorTemplate is below
#model GenericSearch.Models.TextSearch
<table class="form-group container">
<tr class="row">
<td class=" col-sm-2 " style="display: table-cell; vertical-align: middle;height: 50px; ">
#Html.LabelFor(x => x.Label, Model.Label, new { #class = "control-label pull-right" })
</td>
<td class=" col-sm-2 " style="display: table-cell; vertical-align: middle;height: 50px; ">
#Html.DropDownListFor(m => m.Comparators, new SelectList(Model.Comparators, "Value", "Text"), new { #class = "form-control", style = "width:150px" })
</td>
<td class="col-sm-8 form-inline" style="display: table-cell; vertical-align: middle;height: 50px;">
#Html.TextBoxFor(x => x.Value, new { #class = "form-control" })
</td>
</tr>
</table>
I have a razor view for Index as below
#model GenericSearch.Models.Search
<div class="row">
#using (#Html.BeginForm("Index", "Home", FormMethod.Post))
{
{
#Html.EditorFor(m => m.List)
<div class="form-group">
<div class="col-sm-12 text-center">
<button type="submit" class="btn btn-primary">Apply filters</button>
</div>
</div>
}
}
</div>
And two Index action at the controller as below
public ActionResult Index()
{
Search search = new Models.Search();
search.List= new List<BaseSearch>();
TextSearch text = new TextSearch();
text.Label = "Text1";
search.MyProperty.Add(text);
return View(search);
}
[HttpPost]
public ActionResult Index(Search search)
{
return View(search);
}
This setting is rendered fine, however when I fill the rendered text boxes and post it through the submit button, I am expecting to receive the Search class populated with the List<TextSearch> that has properties filled with the values entered by the user at the HttpPost Index. But I get an error saying that this can't be done because BaseClass is abstract, when I remove the abstract keyword from the BaseClass the Search class gets instantiated but with a List<BaseSearch> instead of a List<TextSearch> also it has its properties empty, not filled with the data user entered. What am I missing here?
EDIT
public class Search
{
public List<BaseSearch> List { get; set; }
}
public abstract class BaseSearch
{
string label;
protected List<Comparator> comparators;
public string Label
{
get
{
return label;
}
set
{
label = value;
}
}
public List<Comparator> Comparators
{
get
{
return comparators;
}
set
{
comparators = value;
}
}
public BaseSearch()
{
comparators = new List<Models.Comparator>();
}
}
public class TextSearch : BaseSearch
{
string _value;
public string Value
{
get
{
return _value;
}
set
{
_value = value;
}
}
public TextSearch() : base()
{
comparators.Add(new Comparator() { Value = -1, Text = Resources.Choose });
comparators.Add(new Comparator() { Value = 1, Text = Resources.StartWith });
comparators.Add(new Comparator() { Value = 2, Text = Resources.Contains });
}
}

Related

Models not collecting values from View to HttpPost Controller Method

I am currently trying to pass a list of models from my view to my controller. Currently, I am able to grab each model from the view and place them inside of a list and pass the list within the HttpPost controller ActionResult method. However when doing this, none of the models have their data within them as all of the models have their property values set to either 0 or null.
My code is as follows:
View:
#using (Html.BeginForm("SaveCarouselImageData", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="card shadow">
<div class="card-header border-0">
<div class="row align-items-center">
<div class="col">
<h3 class="mb-0">Homepage Carousel</h3>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table align-items-center table-flush">
<thead class="thead-light">
<tr>
<th></th>
<th scope="col">Image</th>
<th scope="col">Order Num</th>
<th></th>
</tr>
</thead>
<tbody id="carousel-content">
#for (int i = 0; i < Model.Count(); i++)
{
<tr>
<th><input type="number" value="#Model[i].getId()" name="id" hidden readonly /></th>
<th scope="row">
<img src="#Url.Content(Model[i].getImgLoc())" name="imgLoc" class="carousel-img-thumbnail" alt="Image" />
</th>
<td>
#Html.TextBoxFor(model => model[i].orderNum, Model[i].getOrderNum().ToString(), new { type = "number", name = "orderNum" })
</td>
<td>
<a class="btn btn-danger btn-lg btn-block openDeleteModal" data-toggle="modal" href="#deleteImageModal" data-id="#Model[i].getId()">
DELETE
</a>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
<div class="row form-button-group">
<div class="col-md-6 col-sm-12 form-button-padding">
<button type="button" class="btn btn-success btn-lg btn-block" data-toggle="modal" data-target="#addImageModal">
+ Add New Image
</button>
</div>
<div class="col-md-6 col-sm-12 form-button-padding">
<button type="submit" class="btn btn-primary btn-lg btn-block">
Save Changes
</button>
</div>
</div>
}
Controller:
// POST: Saves Carousel Image Data
[HttpPost]
public ActionResult SaveCarouselImageData(List<CarouselModel> images)
{
if (!checkLoginCredentials())
{
return RedirectToAction("Login", "Home");
}
else
{
List<CarouselModel> updatedModels = new List<CarouselModel>();
foreach (CarouselModel img in images)
{
CarouselModel dbModal = siteServices.getCarouselImageById(img.getId());
dbModal.setOrderNum(img.getOrderNum());
}
int result = siteServices.updateCarouselTable(updatedModels);
return RedirectToAction("HomepageCarousel", "Admin");
}
}
Model:
public class CarouselModel
{
[Display(Name="id")]
private int id;
[Display(Name = "imgLoc")]
private string imgLoc;
[Display(Name = "orderNum")]
public int orderNum;
public int getId()
{
return this.id;
}
public string getImgLoc()
{
return this.imgLoc;
}
public int getOrderNum()
{
return this.orderNum;
}
public void setId(int id)
{
this.id = id;
}
public void setImgLoc(string imgLoc)
{
this.imgLoc = imgLoc;
}
public void setOrderNum(int orderNum)
{
this.orderNum = orderNum;
}
}
Again, the models themselves are currently getting passed from the View and into the List for the SaveCarouselImageData method, but all of their property values are null or 0.
Please assist.
all of their property values are null or 0.
I think that's because your CarouselModel's properties lack get;set; which the ASP.NET MVC Binding makes use of by default.
During POST, the binder will try to bind the form values to that of your model, but since it lacks accessors, it can't set any of the values that comes from the form.
Besides that, they're both specified to be Private which can only be accessed within the class, you should use Public if you want them to be set externally.
The easiest solution is to make them Public and add the accessors get;set;:
[Display(Name="id")]
public int id {get;set;}
[Display(Name = "imgLoc")]
public string imgLoc {get;set;}
[Display(Name = "orderNum")]
public int orderNum {get;set;}
If you still want ID and ImgLoc to remain Private then, you could do something like this;
private int _id {get;set;}
private string _imgLoc {get;set;}
[Display(Name = "orderNum")]
public int orderNum;
[Display(Name="id")]
public int id{
get{
return this._id;
}
set{
this._id = value;
}
}
[Display(Name = "imgLoc")]
public string imgLoc{
get{
return this._imgLoc;
}
set{
this._id = value;
}
}
Then change your HTML input fields to use the public properties.

mvc validationMessage is not working while its in IEnumerable<T>

I have a class :
public class Cust
{
[Required(ErrorMessage ="NameField Req")]
public string Name { get; set; }
}
I use this class :
public class CustModel
{
public IEnumerable<Cust> CustList { get; set; }
}
.Cshtml
#model WebApplication2.Models.CustModel
#Html.EditorFor(m => m.CustList)
#Html.ValidationMessageFor(val => val.CustList)
When I hit on Submit button if (ModelState.IsValid){} is working but why my error message is not displayed ?
I managed to re-produce your code, assuming your view:
Please, pay attention to the for loop:
#model MVC_SteckOverflow.Models.ViewModels.CustModel
#using MVC_SteckOverflow.Models.ViewModels
#{
ViewBag.Title = "ValidateIenumerable";
}
<style>
.field-validation-error {
color:#F00;
}
.input-validation-error {
border: 1px solid red;
background-color: #f9e2e2b3;
}
</style>
<h2>ValidateIenumerable</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>CustModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#for (int i = 0; i != Model.CustList.Count(); i++)
{
#Html.EditorFor(x => x.CustList.ToList()[i].Name)
#Html.ValidationMessageFor(x => x.CustList.ToList()[i].Name)
}
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section scripts{
#Scripts.Render("~/bundles/jqueryval")
}
according to the following actions in the Controller:
public ActionResult ValidateIenumerable()
{
CustModel custModel = new CustModel {
CustList = new List<Cust> {
new Cust{ Name = "A"},
new Cust{ Name = "B"},
new Cust{ Name = "C"},
},
};
return View(custModel);
}
[HttpPost]
public ActionResult ValidateIenumerable(CustModel custModel)
{
return View(custModel);
}
The code above, is tested, built and run successfully.
Hope this helped ... :)

How to create view for given model

I am new to asp .net mvc 4.0. i have given model. i am not getting how can i create view for model. I am facing problem at IList JournalEntries. other entry i am able to do.
public class Journal : BaseClass
{
public virtual string VoucherNo { get; set; }
public virtual DateTime VoucherDate { get; set; }
public string VoucherDateView {
get
{
return VoucherDate.ToShortDateString();
}
}
public IList<JournalEntry> JournalEntries { get; set; }
public IList<Ledger> Accounts { get; set; }
public double TotalAmount
{
get
{
double sum = 0;
if (JournalEntries != null && JournalEntries.Count>0)
foreach (var journal in JournalEntries)
sum = journal.Principal + journal.Interest+sum;
return sum;
}
}
}
I have tried below view but add entry doesn't works.
#model Sms.CoreSociety.Journal
#{
ViewBag.Title = "Create";
}
#{
string data = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model);
}
<script type="text/javascript">
$(document).ready(function () {
$('#document').validate();
$("#VoucherDate").mask("99/99/9999", { placeholder: " " });
function entryVm(entries) {
var self = this;
self.entryList = ko.observableArray(entries);
self.entry = ko.observable();
self.rowClick = function(entry1) {
alert("Delete alert");
self.dispatchList.remove(entry1);
};
self.addEntry = function() {
alert("Add alert");
this.entryList.push({ AccountName_AccountHead: "", DebitCredit: "", Principal: "0.0", Interest: "0.0", Narration: ""});
};
}
var models = #Html.Raw(Json.Encode(Model.JournalEntries)) ;
ko.applyBindings(new entryVm(models));
});
</script>
#using (Html.BeginForm(null, null, FormMethod.Post, new Dictionary<string, object>() { { "class", "form-horizontal" }, { "id", "document" } }))
{
#Html.ValidationSummary(true)
<fieldset>
<div class="row">
<div class="span1">
<label>Voucher No</label>
</div>
<div class="span5">
#Html.DisplayFor(model => model.VoucherNo)
</div>
</div>
<div class="row">
<div class="span1">
<label>Voucher Date</label>
</div>
<div class="span5">
#Html.TextBoxFor(model => model.VoucherDate, "{0:dd/MM/yyyy}", new Dictionary<string, object>() { { "class", "required" } })
</div>
</div>
<div class="row">
<div class="span1">
<label>Amount</label>
</div>
<div class="span5">
#Html.DisplayFor(model => model.TotalAmount)
</div>
</div>
<input type="submit" value="Save" class="btn" id="submit"/>
#if (Model.Id != new Guid())
{
<div style="float: right">
<a class="btn btn-danger" href='#Url.Action("Delete")/#Model.Id' aria-hidden="true">Delete</a>
</div>
}
</fieldset>
}
<h4>Journal Entry</h4>
<p >Entry for<span data-bind="text: entryList().length"> </span> entry(s)</p>
<button data-bind="click: addEntry" class="btn">Add Record</button>
<table>
<tbody data-bind="template: { name: 'entryRowTemplate', foreach: entryList }"></tbody>
</table>
<script type="text/html" id="entryRowTemplate">
<tr>
<td>AccountName_AccountHead: \$ <input data-bind="value: AccountName.AccountHead"/> </td>
<td>DebitCredit: \$ <input data-bind="value: DebitCredit"/></td>
<td>Principal: \$ <input data-bind="value: Principal"/></td>
<td>Interest: \$ <input data-bind="value: Interest"/></td>
<td>Narration: \$ <input data-bind="value: Narration"/></td>
<td>Delete</td>
</tr>
</script>
below is my Journal controller
using System;
using System.Linq;
using System.Web.Mvc;
using Sms.CoreSociety;
using System.Collections.Generic;
namespace SmsModernUI.Controllers
{
public class JournalController : BaseController
{
//
// GET: /AccountGroup/
public ActionResult Index()
{
var journals = Repository.GetAll<Journal>().OrderBy(x => x.VoucherNo);
return View(journals);
}
public ActionResult Create(Guid id)
{
if (id == new Guid())
{
var journal = new Journal();
string lastvoucherno = Repository.GetAll<Journal>().OrderBy(x => x.VoucherNo).Last().VoucherNo;
journal.VoucherNo = (int.Parse(lastvoucherno) + 1).ToString();
journal.VoucherDate = System.DateTime.Now;
journal.JournalEntries = new List<JournalEntry>();
journal.Accounts = Repository.GetAll<Ledger>();
return PartialView(journal);
}
var journal1 = Repository.Get<Journal>(id);
journal1.JournalEntries = Repository.GetAll<JournalEntry>(x => x.Journal.Id == id);
journal1.Accounts = Repository.GetAll<Ledger>();
return PartialView(journal1);
}
[HttpPost]
[ValidateInput(false)]
public ActionResult Create(Journal journal)
{
if (journal.Id == new Guid())
{
var jj = Repository.Save(journal);
foreach (var journalentry in journal.JournalEntries)
{
journalentry.Id = jj.Id;
Repository.Save(journalentry);
}
}
else
{
Journal jr = Repository.Get<Journal>(journal.Id);
var entries = Repository.GetAll<JournalEntry>(x=>x.Journal.Id == journal.Id);
foreach (var entry in entries)
{
Repository.Delete(entry);
}
var jj = Repository.Save(journal);
foreach (var journalentry in journal.JournalEntries)
{
journalentry.Id = jj.Id;
Repository.Save(journalentry);
}
}
return RedirectToAction("Index");
}
public ActionResult Index1()
{
Journal journal1 = Repository.Get<Journal>(new Guid("7A6EEBBC-2F3A-4A27-ACF8-A1D40115A68F"));
journal1.JournalEntries = Repository.GetAll<JournalEntry>(x => x.Journal.Id == journal1.Id);
journal1.Accounts = Repository.GetAll<Ledger>();
return View(journal1);
}
public ActionResult Delete(Guid id)
{
Journal jr = Repository.Get<Journal>(id);
var entries = Repository.GetAll<JournalEntry>(x => x.Journal.Id == jr.Id);
foreach (var entry in entries)
{
Repository.Delete(entry);
}
var result = Repository.Delete(jr);
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult Create1(Journal journal)
{
var temp = journal;
return RedirectToAction("Create",journal.Id);
}
}
}
Views are not genereted from models. You need Controller Action method to pass your model to View.
public ActionResult()
{
var model = new Journal
{
//**define here value of model's properties, that you need in View
}
return View(model);
}
EDITED: After your addition.
I would devide it into two parts. Create ViewModel and pass it from View To Controller.
public JurnalViewModel
{
public Journal journal {get; set;}
public IList<JournalEntry> JournalEntries {get; set;}
}
Than in Create action first create journal and after foreach JournalEntries in model create new JournalEntry.
EDITED 2 To your comment. Quick sample:
[HttpPost]
public ActionResult Create (JurnalViewModel model)
{
var journal = new Journal();
db.Journals.Add(journal);
journal.name = model.journal.name
.....
//**some code
db.SaveChanges()
foreach(var item in model.JournalEntries )
{
var entry = new JournalEntry()
db.JournalEntries .Add(entry);
entry.property = item.property;
....
//**some code
db.SaveChanges()
}
}
Your problem is that you have no class constructor for JournalEntries.
public Journal()
{
JournalEntries = new List<JournalEntry>();
Accounts = new List<Ledger>();
}
Right click to your Action method inside controller and click add view then check create strongly typed-view checkbox then choose your desired model from dropdown in displayed dialogue box

how to bind more than one model with single view?

Guys I have tried to use more than one Models with single view.
but I could not found the solution how to implement it.
I want to use One View data in Single past and the other in another part..
I have used the following code..
this is one view
#Html.Partial("Sidebar")
this is another view
<!-- start content -->
<div id="content">
<div class="post">
<h1 class="title">
Add New Post
</h1>
<p></p>
<div class="entry">
#using (Html.BeginForm())
{
<div>
<div style="display:inline;">
<div style="display: inline; float: left;">
#Html.Label("lblcategory", "Category", new { style = "Width:100px; float: left;" })
<div style="width: 150px; height: 60px; overflow-y: scroll; display: inline; float: left;">
#for (int i = 0; i < (int)TempData["Rows"]; i++)
{
for (int j = 0; j < (int)TempData["Cols"]; j++)
{
<input id="Checkbox + #i" name = "Category" type="checkbox" style="width:50px;" value="#TempData["[" + i.ToString() + "][" + j.ToString() + "]"]"/>
#TempData["[" + i.ToString() + "][" + j.ToString() + "]"]
}
}
#*#Html.LabelFor(model => model.CategoryName)*#
</div>
<div style="float:right;">
<label id="lblcategoryrequired" style="color:Red">#Html.ValidationMessageFor(model => model.CategoryName)</label>
</div>
</div>
</div>
<div>
<p style="display: inline; float: left;">
#Html.Label("lblsubjet", "Subject", new { style = "Width:100px; float: left;" })
#*#Html.TextBox("txtsubject", "", new { style = "Width:700px;" })*#
#Html.TextBoxFor(model => model.PostSubject, new { style = "Width:400px; maxlength=400;" })
<label id="lblsubjectrequired" style="color:Red">#Html.ValidationMessageFor(model => model.PostSubject)</label>
</p>
</div>
<div>
<p style="display: inline; float: left;">
#Html.Label("lblcontent", "Content", new { style = "Width:100px; float: left; Vertical-align:top;" })
#*#Html.TextArea("txtcontent","", new { style = "Width:700px; height:200px; maxlength=700;" })*#
#Html.TextAreaFor(model => model.PostContent, new { style = "Width:400px; height:200px; maxlength=400;" })
</p>
</div>
<div>
<p style="display: inline; float: left;">
#Html.Label("lblblank", "a", new { style = "Width:100px; float: left; Color:#372412" })
<input type="submit" value="Add" id="btnadd" style="width: 100px;" class="button" />
&nbsp&nbsp&nbsp&nbsp
<a id="Cancel" href="~/Home/Home"> <input type="button" value="Cancel" id="btncancel" class="button" style="width: 100px;" /></a>
</p>
</div>
</div>
#Html.ValidationSummary(true)
}
</div>
</div>
</div>
</div>
I don't understand your question 100%. But if I were to understand it then I don't think it will work the way that you need it to work (I might be mistaken). I would suggest that you move away from your partial view and just pass in one view model that you can use to populate both sections. View models are there to represent your data on a view.
I'm going to give you a basic sample that you can modify and use in your scenario. Lets say we have a customer and this customer can have 1 or many addresses. So a basic representation of these 2 models could look like this:
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IEnumerable<Address> Addresses { get; set; }
}
public class Address
{
public int Id { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressLine3 { get; set; }
}
And now on your details view you want to display the customer's details and the addresses of this customer. So we have 2 models (customer and address) that you are displaying on 1 view.
public ActionResult Details(int id)
{
Customer customer = customerRepository.GetById(id);
if (customer != null)
{
customer.Addresses = addressRepository.GetAddressesForCustomer(customer.Id);
}
// The above 2 steps can be done in 1 repository call
// Now populate your view model with the above details
// This can also be 1 or 2 lines when you use something like Auto Mapper
CustomerDetailsViewModel viewModel = new CustomerDetailsViewModel
{
viewModel.CustomerId = customer.Id,
viewModel.CustomerFirstName = customer.FirstName,
viewModel.CustomerLastName = customer.LastName,
viewModel.CustomerAddresses = customer.Addresses
};
return View(viewModel);
}
Your view model:
public class CustomerDetailsViewModel
{
public int CustomerId { get; set; }
public string CustomerFirstName { get; set; }
public string CustomerLastName { get; set; }
public IEnumerable<Address> CustomerAddresses { get; set; }
}
So now you have 1 view model populated from 2 different models. Now all that you have to do on your view is to use this view model to display data:
#model YourProject.ViewModels.Customers.CustomerDetailsViewModel
#Model.CustomerId<br />
#Model.CustomerFirstName<br />
#Model.CustomerLastName<br /><br />
#foreach (var address in #Model.CustomerAddresses)
{
<div>
#address.Id<br />
#address.AddressLine1<br />
#address.AddressLine2<br />
#address.AddressLine3<br />
</div>
}
I hope this helps.
You should use a view model that represents the data required to render your view. You could either expose the models directly on the view model (violating LoD), or delegate the calls to the view model to the underlying models (violating the DRY principle).

RadioButton Not Persisting on Submit When There's an Error

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; }
}

Resources