How can I display two partial views in the same view? In my controller I have two methods that both returns partialview. I want these methods together in one view.
In my controller i have this:
public ActionResult CountCars()
{
var result = this.Data.Cars.All()
.Select(t => new CarsViewModel
{
CategoryName = t.Name,
CategoryCount = t.Category.Count()
});
return PartialView("_ChooseCarsPartialViewLayout", result.ToList());
}
public ActionResult ChooseCity()
{
var view = this.Data.Cities.All()
.Select(x => new CityViewModel
{
CityName = x.Name,
CountCities = x.City.Count()
});
return PartialView("_ChooseCarsPartialViewLayout", view.ToList());
}
_ChooseCarsPartialViewLayout
#model IEnumerable<Project.ViewModels.City.CityViewModel> <div class="container">
<div class="well">
<div class="row">
<div class="col-md-12">
<div class="form-group">
<h4>?</h4>
<div class="checkbox checkbox-primary">
#for (int i = 0; i < Model.Count(); i++)
{
var cars = Model.ElementAt(i);
<label>#cars.CategoryName <span class="badge">#cars.CategoryCount</span></label>
#Html.RadioButton(cars.CategoryName,
cars.CategoryId,
new
{
id = "radio",
type = "checkbox"
})
}
</div>
</div>
<div class="form-group">
<h4>Hvor vil du jobbe?</h4>
<div class="checkbox checkbox-primary">
#for (int i = 0; i < Model.Count(); i++)
{
var city = Model.ElementAt(i);
<label>#city.CityName <span class="badge">#city.CountCities</span></label>
#Html.RadioButton(city.CityName,
city.CityId,
new
{
id = "radio",
type = "checkbox"
})
}
</div>
</div>
</div>
</div>
</div>
And when I run the solution it just display an error that says.
Value cannot be null or empty.
Parameter name: name
Line 18: #Html.RadioButton(cars.CategoryName,
But if I had two different partial views then it works great, but I want to have this in the same partialview.
Also I have this Html.Action in _Layout to render the partialviews
#Html.Action("ChooseCity", "Home")
Any suggestion?
Problem is with the partial view model which is strongly typed of IEnumerable<Project.ViewModels.City.CityViewModel> which does not contain the declaration of CategoryName. So, you should create a Composite Model which would return Cars and Citis to partial view.
public class CompositeModel
{
public IEnumerable<Project.ViewModels.City.CityViewModel> Cars { get; set; }
public IEnumerable<Project.ViewModels.City.CarsViewModel> Cities { get; set; }
}
Now change your view as
#model CompositeModel
<div class="container">
<div class="well">
<div class="row">
<div class="col-md-12">
<div class="form-group">
<h4>?</h4>
<div class="checkbox checkbox-primary">
#for (int i = 0; i < Model.Cars.Count(); i++)
{
var cars = Model.Cars.ElementAt(i);
<label>#cars.CategoryName <span class="badge">#cars.CategoryCount</span></label>
#Html.RadioButton(cars.CategoryName,
cars.CategoryId,
new
{
id = "radio",
type = "checkbox"
})
}
</div>
</div>
<div class="form-group">
<h4>Hvor vil du jobbe?</h4>
<div class="checkbox checkbox-primary">
#for (int i = 0; i < Model.Cities.Count(); i++)
{
var city = Model.Cities.ElementAt(i);
<label>#city.CityName <span class="badge">#city.CountCities</span></label>
#Html.RadioButton(city.CityName,
city.CityId,
new
{
id = "radio",
type = "checkbox"
})
}
</div>
</div>
</div>
</div>
</div>
Since you have a ViewModel called CityViewModel (though I'll name it RadiosVM I would create a few EditorFor templates.
Use a composite model as user1672994 mentioned in his answer although it can be made more generic and reusable. A ViewModel should encapsulate all (there are exceptions) the data necessary to render a view.
public class RadiosVM
{
public string Name { get; set; }
public IEnumerable<RadioVM> Radios { get; set; }
}
public class RadioVM
{
public string Name { get; set; }
public int Count { get; set; }
}
public class SomePageVM // whatever
{
public RadiosVM CarRadios { get; set; }
public RadiosVM CityRadios { get; set; }
// ... other properties
}
Don't spin up another controller just to display a model (that is inefficient), unless the controller is doing things that have absolutely nothing to do with the current controller and/or you plan on caching that view.
public class SomeController
{
public ActionResult SomePage()
{
var model = new SomePageVM();
model.CarRadios = GetCarRadios;
model.CityRadios = GetCityRadios;
return View(model);
}
private RadiosVM GetCarRadios()
{
var result = new RadiosVM()
{
Name = "Cars",
Radios = this.Data.Cars.All()
.Select(t => new RadioVM
{
CategoryName = t.Name,
CategoryCount = t.Category.Count()
})
.ToList();
}
return result;
}
public RadiosVM ChooseCity()
{
var result = new RadiosVM ()
{
Name = "Cars",
Radios = this.Data.Cities.All()
.Select(t => new RadioVM
{
CategoryName = t.Name,
CategoryCount = t.Category.Count()
})
.ToList();
}
return result;
}
Views:
SomePage.cshtml
#Model SomePageVM
<div class="well">
<div class="row">
<div class="col-md-12">
#Html.EditorFor(m => m.CarRadios)
<div/>
<div class="col-md-12">
#Html.EditorFor(m => m.CityRadios)
<div/>
// ...
/Views/Shared/EditorTemplates/RadiosVM.cshtml
or
/Views/SomeController/EditorTemplates/RadiosVM.cshtml
#Model RadiosVM
<div class="form-group">
<h4>#Html.DisplayFor(m => m.Name)</h4>
<div class="checkbox checkbox-primary">
#Html.DisplayFor(m => m.Radios)
</div>
/Views/Shared/EditorTemplates/RadioVM.cshtml
or
/Views/SomeController/EditorTemplates/RadioVM.cshtml
#Model RadioVM
<label>#Html.DisplayFor(m => m.Name)
<span class="badge">#Html.DisplayFor(m => m.Count)</span>
</label>
#Html.RadioButton(model.Name,
model.Id, // You have no code that references this, I don't know...
new
{
id = "radio", // so **ALL** radios are named 'id'?? not valid
type = "checkbox"
})
Related
I'm trying to return a category page with paging .... I got a problem with that in my view , I can't handle the View Model Members , and can't to control them ...
Here is my ViewModel:
public class CategoryVm
{
public List<Book> Book { set; get; }
public Category Category_Content { get; set; }
}
Also here is the controller :
public ActionResult Category(int? id, int? page)
{
int pageSize = 6;
int pageNumber = page ?? 1;
if (id != null)
{
var vm = new CategoryVm();
vm.Category_Content = db.Categories.Where(t => t.Category_id == id).Single();
vm.Book = db.Books.Where(b => b.Category_id == id).ToList();
if (vm != null)
{
//Here I have the problem , it telling me that 'CategoryVm' does not contain a definition for 'ToPagedList'
return View(vm.ToPagedList(pageNumber, pageSize));
}
return HttpNotFound();
}
return RedirectToAction("index",new { Controller = "Home" });
}
and here is my view :
#using PagedList.Mvc
#model PagedList.IPagedList<SmartBookLibrary.ViewModel.CategoryVm>
#{
ViewBag.Title = Model.Category_Content.Category_name+ " - Smart Books Library";
}
<div class="container">
<div class="row">
<div class="col-md-3">
<p class="lead">Categories</p>
<div class="list-group">
Developers
</div>
</div>
<div class="col-md-9">
<div class="row">
#foreach (var item in Model.Book)
{
<div class="col-sm-4 col-lg-4 col-md-4">
<figure class="snip1091 navy">
<img src="~/Images/#item.Book_Image" alt="sq-sample6" />
<figcaption>
<label>#item.Book_name</label>
</figcaption>
</figure>
</div>
}
</div>
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("Category", new {page}))
</div>
</div>
</div>
I the view I can't access the model :
ViewBag.Title = Model.Category_Content
#foreach (var item in Model.Book)
so how to fix that , and make the paging work ??
Update your view model to use the Paged list
public class CategoryVm {
public IPagedList<Book> Book { set; get; }
public Category Category_Content { get; set; }
}
Then assign the paged list to your view model
public ActionResult Category(int? id, int? page) {
int pageSize = 6;
int pageNumber = page ?? 1;
if (id != null) {
var vm = new CategoryVm();
vm.Category_Content = db.Categories.Where(t => t.Category_id == id).Single();
var books = db.Books.Where(b => b.Category_id == id).ToList();
if (vm != null) {
//Apply paged list to view model.
vm.Books = books.ToPagedList(pageNumber, pageSize);
return View(vm);
}
return HttpNotFound();
}
return RedirectToAction("index",new { Controller = "Home" });
}
Now in your view change the model.
#model SmartBookLibrary.ViewModel.CategoryVm
And
Page #(Model.Book.PageCount < Model.Book.PageNumber ? 0 : Model.Book.PageNumber) of #Model.Book.PageCount
#Html.PagedListPager(Model.Book, page => Url.Action("Category", new {page}))
According to here ToPageList will be applied to IEnumerable or IQueryable:
https://github.com/troygoode/PagedList
var vm = new CategoryVm();
vm.Category_Content = db.Categories.Where(t => t.Category_id == id).Single();
vm.Book = db.Books.Where(b => b.Category_id == id).ToList();
if (vm != null)
{
var newListCategoryVm = new List<CategoryVm>() {vm}
return View(newListCategoryVm.ToPagedList(pageNumber, pageSize));
}
In the view you know now that you need to for each or whatever you like.
I followed this tutorial to add & remove multiple textbox: http://www.itorian.com/2013/04/nested-collection-models-in-mvc-to-add.html. I want to know how to use multiple templates for "EditorFor".
In my Chemical model:
public partial class NPG_Chemical
{
public NPG_Chemical()
{
this.NPG_Chemical_Measurement_Methods = new HashSet<NPG_Chemical_Measurement_Method>();
}
public virtual ICollection<NPG_Chemical_Measurement_Method> NPG_Chemical_Measurement_Methods { get; set; }
internal void CreateMeasurementMethods(int count = 1)
{
for (int i = 0; i < count; i++)
{
NPG_Chemical_Measurement_Methods.Add(new NPG_Chemical_Measurement_Method());
}
}
In my Chemical controller:
public ActionResult Create()
{
var nPG_Chemical = new NPG_Chemical();
nPG_Chemical.CreateMeasurementMethods(1);
return View(nPG_Chemical);
}
In my Create.cshtml:
<div id="type1s">
<label>
Type1:
</label>
#Html.EditorFor(model => model.NPG_Chemical_Measurement_Methods)
</div>
<div id="type2s">
<label>
Type2:
</label>
#Html.EditorFor(model => model.NPG_Chemical_Measurement_Methods)
</div>
and I have a template: NPG_Chemical_Measurement_Method.cshtml
#model NPG_Administrative_Utility.Models.NPG_Chemical_Measurement_Method
<div class="type1" style="display:inline-block;">
<p>type1
#Html.Hidden("Measurement_Type", "Type1")
#Html.TextBoxFor(x => x.Measurement_Method)
</p>
</div>
The problem is how can I use another template which include the following code for type 2 EditorFor:
#model NPG_Administrative_Utility.Models.NPG_Chemical_Measurement_Method
<div class="type2" style="display:inline-block;">
<p>type2
#Html.Hidden("Measurement_Type", "Type2")
#Html.TextBoxFor(x => x.Measurement_Method)
</p>
</div>
Now these two EditorFor will all use the first template.
I believe what you want is a partial view.
I have created an editor template base on this article ASP.NET MVC: Annotated for Input by Dino Esposito
Everything works fine until i press the submit button. I find out that my POST function return model is NULL, its like the model is not bind to the view. I have been trying all trick that I know and I found from the internet but I still can't fix it.
This is my controller
// GET: /Asset/New
public ActionResult New()
{
ViewBag.typeID = new SelectList(db.Ref_Asset_Types, "ID", "name");
return View(new AssetViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult New(AssetViewModel vm)
// vm.asset should contain new value but currently return null
{
if (ModelState.IsValid)
{
db.Assets.Add(vm.asset);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.typeID = new SelectList(db.Ref_Asset_Types, "ID", "name", vm.asset.typeID);
return View("New", vm);
}
this is my view
#using (Html.BeginForm("New","Asset","POST")) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.EditorFor(m=>m.asset, "InputTemplate" )
// note : the code works if i don't use my own template ==> #Html.EditorFor(m=>m.asset)
<div class="form-actions btn pull-right">
#Html.ActionLink("Back to List", "Index", null, new { #class = "btn btn-sm"})
<button type="reset" class="btn btn-sm" value="Index">
Reset
</button>
<button type="submit" class="btn btn-sm btn-success">
<i class="glyphicon glyphicon-plus"></i>
Tambah
</button>
</div>
}
and this is my InputTemplate
#inherits System.Web.Mvc.WebViewPage
#if (Model == null)
{
<span>#ViewData.ModelMetadata.NullDisplayText</span>
}
else
{
foreach (var prop in ViewData
.ModelMetadata
.Properties
.Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm)))
{
if (prop.DisplayName != null) { // only display prop not of ComplexType
// note : using bootstrap for css styling
<div class="form-group col-xs-6">
<label class="col-xs-4 control-label text-right">
<span style="color:red"> #(prop.IsRequired ? "*" : "") </span>
<span>#prop.GetDisplayName()</span>
</label>
<div class="col-xs-8">
#if(prop.IsReadOnly)
{
<span class="readonly-field">#Html.Display(prop.PropertyName)</span>
}
else if (prop.TemplateHint == "DropDown")
{
<span>#Html.DropDownList(prop.PropertyName,(IEnumerable<SelectListItem>) ViewData[prop.PropertyName], new { #class = "form-control" })</span>
<span>#Html.ValidationMessage(prop.PropertyName)</span>
}
else
{
<div class="editor-field">
<span>#Html.Editor(prop.PropertyName, new { #class = "text-box single-line form-control" })</span>
<span>#Html.ValidationMessage(prop.PropertyName, new { #class = "label-danger" } )</span>
</div>
}
</div>
</div>
} // if
} // foreach
}
This is my viewmodel
using System;
using SIGMA.Models;
namespace SIGMA.ViewModels
{
public class AssetViewModel
{
public AssetViewModel()
{
asset = new Asset();
}
public Asset asset { get; set; }
}
}
This is my model
public class Asset
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
[HiddenInput(DisplayValue = false)]
public int ID { get; set; }
[DisplayName("No. Siri")]
[StringLength(45)]
public string serial_num { get; set; }
[DisplayName("Model")]
[Required(ErrorMessage = "Model perlu diisi!")]
[StringLength(45)]
public string model { get; set; }
[DisplayName("Harga Seunit")]
[RegularExpression(#"^\d{0,6}(\.\d{2})?$", ErrorMessage = "Sila gunakan format harga yang betul.")]
public float? unit_cost { get; set; }
[UIHint("DropDown")]
[DisplayName("Jenis Aset")]
[Required(ErrorMessage = "Jenis aset perlu dipilih!")]
[DisplayFormat(NullDisplayText = "Belum didaftar")]
public int? typeID { get; set; }
public virtual Ref_Asset_Type type { get; set; }
}
Sorry guys for the trouble.. i think i solve it.
My biggest mistake is using reserved word 'model' and 'type' as my property name. This some how cause problem to asp.net in interpreting my model using the user define editor template.
Once I change my property name - model to model_name and type to asset_type, i can see the my entry in my return model already.
Thanks to all
.... spends the whole day and night for this silly mistake but the lesson learn is worth it
I have a complex view model that I am passing to a create view. When I enter data on the page and post it the model is empty. Both the fields in the sub-object and the "test" field are empty. Why?
public class ContactIncident
{
[Key]
public int Id { get; set; }
[DataType(DataType.MultilineText)]
public string Description { get; set; }
[Display(Name = "Incident Date")]
[DataType(DataType.Date)]
public DateTime? IncidentDateTime { get; set; }
[Display(Name = "Follow Up Date")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
[DataType(DataType.Date)]
public DateTime? FollowUpDate { get; set; }
}
public class IncidentManager
{
public ContactIncident Incident { get; set; }
public string Test { get; set; }
}
public ActionResult Create(int? id)
{
IncidentManager im = new IncidentManager();
ContactIncident ci = new ContactIncident();
ci.IncidentDateTime = DateTime.Now;
ci.FollowUpDate = DateTime.Now.AddDays(14);
im.Incident = ci;
return View(im);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(IncidentManager im)
{
if (ModelState.IsValid)
{
ContactIncident ci = new ContactIncident();
ci.IncidentDateTime = incident.Incident.IncidentDateTime;
ci.Description = im.Incident.Description;
return RedirectToAction("Index");
}
return View(incident);
}
View:
#model MyApp.Web.ViewModels.IncidentManager
#{
ViewBag.Title = "Edit Incident";
}
<h4>#ViewBag.Title</h4>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal well">
#Html.ValidationSummary(true)
#Html.EditorFor(model=>model.Test)
<div class="row">
<div class="col-md-2">
#Html.LabelFor(model => model.Incident.IncidentDateTime)
</div>
<div class="col-md-2">
#Html.DisplayFor(model => model.Incident.IncidentDateTime)
</div>
</div>
<div class="row">
<div class="col-md-2">
#Html.LabelFor(model => model.Incident.Description)
</div>
<div class="col-md-10">
#Html.EditorFor(model => model.Incident.Description, new { htmlAttributes = new { #class = "form-control", rows = "5" }, })
</div>
<div class="col-md-2">
#Html.LabelFor(model => model.Incident.FollowUpDate)
</div>
<div class="col-md-2">
#Html.EditorFor(model => model.Incident.FollowUpDate, new { htmlAttributes = new { #class = "form-control"}, })
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
}
The problem is that the DefaultModelBinder won't be able to map nested models properly if you use a different parameter name. You must use the same parameter name as the ViewModel name.
public ActionResult Create(IncidentManager incidentManager)
As a general practice, always use the name of the model as the parameter name to avoid mapping problems.
UPDATE:
The DefaultModelBinder uses "convention based" mapping.
IncidentManager.Incident = incidentManager.Incident (will map)
IncidentManager.Incident = im.Incident //won't map because 'im' != 'incidentManager'
I'm rather new to the ASP.net MVC world and I'm trying to figure out how to render a group of checkboxes that are strongly typed to a view model. In webforms I would just use the checkboxlist control but im a bit lost with MVC.
I'm building a simple contact form for a wedding planning business and need to pass whatever checkbox values the user selects to my controller.
The form checkboxes need to look like this:
Your help would be greatly appreciated. Thanks!
Here's what I have so far.
CONTROLLER
[HttpPost]
public ActionResult Contact(ContactViewModel ContactVM)
{
if (!ModelState.IsValid)
{
return View(ContactVM);
}
else
{
//Send email logic
return RedirectToAction("ContactConfirm");
}
}
VIEW MODEL
public class ContactViewModel
{
[Required]
public string Name { get; set; }
[Required]
public string Phone { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Required]
public string Subject { get; set; }
public IEnumerable<SelectListItem> SubjectValues
{
get
{
return new[]
{
new SelectListItem { Value = "General Inquiry", Text = "General Inquiry" },
new SelectListItem { Value = "Full Wedding Package", Text = "Full Wedding Package" },
new SelectListItem { Value = "Day of Wedding", Text = "Day of Wedding" },
new SelectListItem { Value = "Hourly Consultation", Text = "Hourly Consultation" }
};
}
}
//Not sure what I should do for checkboxes...
}
VIEW
#model NBP.ViewModels.ContactViewModel
#{
ViewBag.Title = "Contact";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm())
{
<div id="ContactContainer">
<div><span class="RequiredField">* </span>Your Name:</div>
<div>
#Html.TextBoxFor(model => model.Name)
</div>
<div><span class="RequiredField">* </span>Your Phone:</div>
<div>
#Html.TextBoxFor(model => model.Phone)
</div>
<div><span class="RequiredField">* </span>Your Email:</div>
<div>
#Html.TextBoxFor(model => model.Email)
</div>
<div>Subject:</div>
<div>
#Html.DropDownListFor(model => model.Subject, Model.SubjectValues)
</div>
<div>Vendor Assistance:</div>
<div>
<!-- CHECKBOXES HERE -->
</div>
<div>
<input id="btnSubmit" type="submit" value="Submit" />
</div>
</div>
}
You could enrich your view model:
public class VendorAssistanceViewModel
{
public string Name { get; set; }
public bool Checked { get; set; }
}
public class ContactViewModel
{
public ContactViewModel()
{
VendorAssistances = new[]
{
new VendorAssistanceViewModel { Name = "DJ/BAND" },
new VendorAssistanceViewModel { Name = "Officiant" },
new VendorAssistanceViewModel { Name = "Florist" },
new VendorAssistanceViewModel { Name = "Photographer" },
new VendorAssistanceViewModel { Name = "Videographer" },
new VendorAssistanceViewModel { Name = "Transportation" },
}.ToList();
}
[Required]
public string Name { get; set; }
[Required]
public string Phone { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Required]
public string Subject { get; set; }
public IEnumerable<SelectListItem> SubjectValues
{
get
{
return new[]
{
new SelectListItem { Value = "General Inquiry", Text = "General Inquiry" },
new SelectListItem { Value = "Full Wedding Package", Text = "Full Wedding Package" },
new SelectListItem { Value = "Day of Wedding", Text = "Day of Wedding" },
new SelectListItem { Value = "Hourly Consultation", Text = "Hourly Consultation" }
};
}
}
public IList<VendorAssistanceViewModel> VendorAssistances { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new ContactViewModel());
}
[HttpPost]
public ActionResult Index(ContactViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
//Send email logic
return RedirectToAction("ContactConfirm");
}
}
View:
#using (Html.BeginForm())
{
<div id="ContactContainer">
<div><span class="RequiredField">* </span>Your Name:</div>
<div>
#Html.TextBoxFor(model => model.Name)
</div>
<div><span class="RequiredField">* </span>Your Phone:</div>
<div>
#Html.TextBoxFor(model => model.Phone)
</div>
<div><span class="RequiredField">* </span>Your Email:</div>
<div>
#Html.TextBoxFor(model => model.Email)
</div>
<div>Subject:</div>
<div>
#Html.DropDownListFor(model => model.Subject, Model.SubjectValues)
</div>
<div>Vendor Assistance:</div>
<div>
#for (int i = 0; i < Model.VendorAssistances.Count; i++)
{
<div>
#Html.HiddenFor(x => x.VendorAssistances[i].Name)
#Html.CheckBoxFor(x => x.VendorAssistances[i].Checked)
#Html.LabelFor(x => x.VendorAssistances[i].Checked, Model.VendorAssistances[i].Name)
</div>
}
</div>
<div>
<input id="btnSubmit" type="submit" value="Submit" />
</div>
</div>
}
Use a string array in your view model. You can then use the helper I hacked together. if you don't want to use the helper and the enum then see the actual Html at the bottom. The binder will return a string array with only the selected string values in it. if none are selected it returns a null value for your array. You must account for that, you have been warned :)
View Model:
[Display(Name = "Which Credit Cards are Accepted:")]
public string[] CreditCards { get; set; }
Helper:
public static HtmlString CheckboxGroup<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> propertySelector, Type EnumType)
{
var groupName = GetPropertyName(propertySelector);
var modelValues = ModelMetadata.FromLambdaExpression(propertySelector, htmlHelper.ViewData).Model;//propertySelector.Compile().Invoke(htmlHelper.ViewData.Model);
StringBuilder literal = new StringBuilder();
foreach (var value in Enum.GetValues(EnumType))
{
var svalue = value.ToString();
var builder = new TagBuilder("input");
builder.GenerateId(groupName);
builder.Attributes.Add("type", "checkbox");
builder.Attributes.Add("name", groupName);
builder.Attributes.Add("value", svalue);
var contextValues = HttpContext.Current.Request.Form.GetValues(groupName);
if ((contextValues != null && contextValues.Contains(svalue)) || (modelValues != null && modelValues.ToString().Contains(svalue)))
{
builder.Attributes.Add("checked", null);
}
literal.Append(String.Format("</br>{1} <span>{0}</span>", svalue.Replace('_', ' '),builder.ToString(TagRenderMode.Normal)));
}
return (HtmlString)htmlHelper.Raw(literal.ToString());
}
private static string GetPropertyName<T, TProperty>(Expression<Func<T, TProperty>> propertySelector)
{
var body = propertySelector.Body.ToString();
var firstIndex = body.IndexOf('.') + 1;
return body.Substring(firstIndex);
}
HTML:
#Html.CheckboxGroup(m => m.CreditCards, typeof(VendorCertification.Enums.CreditCardTypes))
Use this if helper extensions scare you:
<input id="CreditCards" name="CreditCards" type="checkbox" value="Visa"
#(Model.CreditCards != null && Model.CreditCards.Contains("Visa") ? "checked=true" : string.Empty)/>
<span>Visa</span><br />
<input id="CreditCards" name="CreditCards" type="checkbox" value="MasterCard"
#(Model.CreditCards != null && Model.CreditCards.Contains("MasterCard") ? "checked=true" : string.Empty)/>
<span>MasterCard</span><br />
For me this works too, and I think this is the simplest (reading the previous answers).
The viewmodel has a string[] for the check boxes.
public string[] Set { get; set; }
The view has this code, and you can repeat the input as many times you need. name, id of the input control has to match the name of the property of the viewmodel.
<div class="col-md-3">
<div class="panel panel-default panel-srcbox">
<div class="panel-heading">
<h3 class="panel-title">Set</h3>
</div>
<div class="panel-body">
<div class="form-group-sm">
<label class="control-label col-xs-3">1</label>
<div class="col-sm-8">
<input type="checkbox" id="Set" name="Set" value="1" />
</div>
<label class="control-label col-xs-3">2</label>
<div class="col-sm-8">
<input type="checkbox" id="Set" name="Set" value="2" />
</div>
</div>
</div>
</div>
</div>
On the post method the Set variable is an array, having the checked value(s).