For some reason my ViewData outputs HTML code even though I don't want it do.
This is what it
<br />2015-04-01
<br />2015-04-02
<br />2015-04-07
<br />2015-04-08
<br />2015-04-09
<br />2015-04-10
but I just want it to look like this
Du har ej rapporterat tid följande dagar:
2015-04-01
2015-04-02
2015-04-07
2015-04-08
2015-04-09
2015-04-10
This is part of my controller:
var missingdays = new DatabaseLayer().GetConsultantMissingDays(Constants.CurrentUser(User.Identity.Name));
if (missingdays.Count == 0)
{
ViewData["missingDays"] = "";
}
else
ViewData["missingDays"] = "Du har ej rapporterat tid följande dagar:<br />" +
string.Join("<br />", missingdays.Select(x => x.ToMissingDateJavascript()));
ViewData.Model = projectData;
return View();
}
And this is from my view:
<div>
#ViewData["missingDays"]
#Html.ValidationSummary()
</div>
and my Extensions
public static string ToMissingDateJavascript(this DateTime value) {
string dateString = value.ToString("yyyy-MM-dd");
return "" + dateString + "";
}
public static bool IsWeekend(this DateTime value) {
return value.DayOfWeek == DayOfWeek.Saturday || value.DayOfWeek == DayOfWeek.Sunday;
}
But I see the HTML code in the browser
You can wrap the call in Html.Raw(), like this:
#Html.Raw(ViewData["missingDays"])
However, it is better to pass in an array rather than HTML (or even passing it in the view model). You should avoid using any HTML in your controller as much as possible. For example:
#foreach(var date in (List<DateTime>)ViewData["stuff"])
{
<a href="javascript:SetDate('#date.ToString("yyyy-MM-dd")');">
#date.ToString("yyyy-MM-dd")
</a>
<br/>
}
Noet: I would also suggest not using br tags here and format with CSS.
In MVC the View is supposed to execute all work related to generating HTML, not the Controller. You can rewrite and simplify both the view and the controller as follows:
View:
#foreach(var date in ViewBag.MissingDays){
var isoDate=date.ToString("yyyy-MM-dd");
<br/>#isoDate
}
Controller:
//Assuming that missingdays is a List<DateTime> or other IEnumerable<DateTime>
ViewBag.MissingDays=missingdays;
You'll need to convert the string to HTML:
#{
string missingDays = ViewData["missingDays"]
}
#MvcHtmlString.Create(missingDays)
Related
We are working on Kendo MVC UI, where we are sending the data from one view to another view, all the data(testbox, dropdown) are getting passed to the next view except the attachments(pdf,xlsx).
Below is the code which in the controller which we have written to capture from view and save the data and pass the same data to the another view and bind the data to the kendo controls(upload control also)
public ActionResult SaveData(System.Web.Mvc.FormCollection form, IEnumerable<HttpPostedFileBase> files) // insert operation
{
//*************************//
if (form != null)
{
string ddluserexceptioncategory = Convert.ToString(form["txtexceptioncategory"], CultureInfo.InvariantCulture);
if (!string.IsNullOrEmpty(ddluserexceptioncategory))
{
ddluserexceptioncategory = ddluserexceptioncategory.Trim();
}
if (ddluserexceptioncategory == "User Management")
{
//Bind the data to the class object(_clsObj)
if (files != null)
{
TempData["FileName"] = files;
_clsObj.Files = files;
}
TempData["SecondViewData"] = _clsObj;
return RedirectToAction("ExceptionType", "Home", new { id = 0, regionId = _clsObj.RegionId, status1 = "New,In Progress", keyword1 = string.Empty });
}
}
string regions = "", statusValue = "";
if (form != null)
{
regions = form["hiddenregionselected"] + "";
statusValue = form["hiddenstatusselected"] + "";
}
return RedirectToAction("homepage", "Home", new { region = regions, status = statusValue });
}
Below is the code which we bind the request to the second
#if (TempData["FileName"] != null)
{
IEnumerable<HttpPostedFileBase> firstFile = (IEnumerable<HttpPostedFileBase>)TempData["FileName"];
<div class="k-dropzone">
<div class="k-button k-upload-button">
<input name="files" type="file" data-role="upload" multiple="multiple" autocomplete="off" tabindex="-1" class="valid" style="display: none;">
<input id="files" name="files" type="file" data-role="upload" multiple="multiple" autocomplete="off">
<ul id="files1" class="k-upload-files k-reset">
#foreach (var file in firstFile)
{
string filename= Path.GetFileName(file.FileName);
<li class="k-file" data-uid="7aa03676-4dac-468e-b34a-99ac44d23040">
<span class="k-icon k-success">uploaded</span>
<span class="k-filename" title="#filename">#filename</span>
<strong class="k-upload-status">
<span class="k-icon k-delete"></span>
</strong>
</li>
}
</ul>
</div>
</div>
<script>
jQuery(function()
{jQuery("#files").kendoUpload(
{"select":uploadselect,
"localization":{"select":"Browse file",
"headerStatusUploading":"uploading..",
"headerStatusUploaded":"uploded.."},
"async":{"saveUrl":"/Home/Save",
"autoUpload":false,"removeUrl":
"/Home/Remove"}});});
</script>
}
else
{
#(Html.Kendo().Upload().Name("files").Async(a => a.Save("Save", "Home").Remove("Remove", "Home").AutoUpload(false)).Multiple(true).Messages(m =>
{
m.Select("Browse file");
}).Events(events => events.Select("uploadselect")))
}
Any suggestions or help is much appreciated.
My guess is that the issue is coming from using TempData to get this data from your markup to your controller or vice versa.
As you are likely aware, anything you put into TempData is discarded after the next request completes (Using Tempdata in ASP.NET MVC - Best practice, http://www.codeproject.com/Articles/476967/What-is-ViewData-ViewBag-and-TempData-MVC-Option).
I would suggest to try using the ViewBag to prove this theory. If it proves out you might think about passing this data as part of a complex object instead of using MVC's data dictionaries.
I have the following code in a Razor Helper file
#helper MakeNoteBlank(string content)
{
string msg = "";
if(content == null)
{
msg = " ";
}
else
{
msg = content;
}
<div class="note">
<p>
#Html.Raw(msg)
</p>
</div>
}
The code fails at execution with the #Html.Raw(..) statement, stating that
"Object reference not set to an instance of an object."
If I remove the #Html.Raw(..) and output 'msg' directly then there is no problem.
What am I doing wrong?
use #(new HtmlString()) instead of #Html.Raw()
The best approach I can think of would possibly be creating an extension method for HtmlHelper. You need to create a class like this:
using System.Web;
using System.Web.Mvc;
namespace MyApplication.Extensions
{
public static class HtmlHelperExtension
{
public static IHtmlString DisplayMessage<T>(this HtmlHelper<T> htmlHelper, string content)
{
return htmlHelper.Raw($#"
<div class=""note"">
<p>
{content ?? " "}
</p>
</div>
");
}
}
}
Then in your cshtml file, simply use it like this:
#using MyApplication.Extensions;
#Html.DisplayMessage("Your content here")
Hope this helps.
I've started playing with Ajax and found a (hopefully) little problem I can't seem to find an answer to.
I generate a list of Ajax forms on my page, the code looks like this
using (Ajax.BeginForm("FixTranslation", new { translationId = errorGroup.Key.Id }, new AjaxOptions { UpdateTargetId = "targetCell_" + errorList.Key.Id }))
{
<table>
<tbody>
<tr><td>#errorGroup.SourceText</td></tr>
<tr><td id="#("targetCell_" + errorGroup.Id)"><input type="text" name="text" id="#("target_" + errorGroup.Id)" value="#(errorGroup.TargetText.Replace(' ', (char)0x00A0))" /><input type="submit" value="Fix" /></td></tr>
#foreach (var error in errorGroup.Value)
{
<tr><td>#error.Description</td></tr>
}
</tbody>
</table>
}
In the controller I have this action:
public ActionResult FixTranslation(string projectId, int translationId, string text)
{
if (Request.IsAjaxRequest())
{
return Content("You entered: " + new HtmlString(text));
}
return RedirectToAction("GetProjectOverview", new { projectId = projectId });
}
This works fine when there are no angle brackets present in the input field, the form gets sent properly. But when there are some angle brackets (e.g. "This is text with <1>tags") in the input field, my action method does not get called at all.
Does anybody know why this is happening?
Thank you very much.
Solved. It was not specific to Ajax forms and the cause has been a request validation, which can be turned off in this way for a particular action method:
[ValidateInput(false)]
public ActionResult FixTranslation(string projectId, int translationId, string text)
{
...
}
I'm working on a non-profit donation platform and I'm using MVC for the first time. I've got the hang of it for the most part but right now I'm having a problem that I dont know how to address. I'm using the AthorizeNet.Helpers class and when I add the code from the expamples, it works for the most part except for it takes the form and puts it ABOVE the tag however it puts the form fields in the correct place. I'm trying to figure out how to render the tag in the correct place.
#using AuthorizeNet.Helpers;
#using (Html.BeginSIMForm("http://127.0.0.1:4768", 1.99M, "xxx_key", "yyy_key", true))
{
#Html.Raw(Html.CheckoutFormInputs(true))
#Html.Hidden("order_id", "1234")
<input type = "submit" value = "Pay" />
}
This is how it looks in HTML output:
<form action = 'https://test.authorize.net/gateway/transact.dll' method = 'post'>
<input type = 'hidden' name = 'x_fp_hash' value = '6bef386eaa89944efd62b47b86042910' \>
<input type = 'hidden' name = 'x_fp_sequence' value = '117'\>
<input type = 'hidden' name = 'x_fp_timestamp' value = 'xxx_key' \>
<input type = 'hidden' name = 'x_login' value = 'yyy_key' \>
<input type = 'hidden' name = 'x_amount' value = '1.99' \>
<input type = 'hidden' name = 'x_relay_url' value = 'http://127.0.0.1:4768' \>
<input type = 'hidden' name = 'x_relay_response' value = 'TRUE' \>
</form><!DOCTYPE html>
<html>
<body>
<h2>Payment Information</h2>
<div style = 'border: 1px solid #990000; padding:12px; margin-bottom:24px; background-color:#ffffcc;width:300px'>Test Mode</div>
<div style = 'float:left;width:250px;'>
<label>Credit Card Number</label>
<div id = 'CreditCardNumber'>
<input type = 'text' size = '28' name = 'x_card_num' value = '4111111111111111' id = 'x_card_num'/>
</div>
</div>
<div style = 'float:left;width:70px;'>
<label>Exp.</label>
<div id = 'CreditCardExpiration'>
<input type = 'text' size = '5' maxlength = '5' name = 'x_exp_date' value = '0116' id = 'x_exp_date'/>
</div>
</div>
<div style = 'float:left;width:70px;'>
<label>CCV</label>
<div id = 'CCV'>
<input type = 'text' size = '5' maxlength = '5' name = 'x_card_code' id = 'x_card_code' value = '123' />
</div>
</div><input id="order_id" name="order_id" type="hidden" value="1234" /> <input type = "submit" value = "Pay" />
This is how I fixed it.
As you stated, add #Html.Raw() around Html.CheckoutFormInputs(true)
The other change to make is in
namespace AuthorizeNet.Helpers -> CheckoutFormBuilders.cs
add a using of
using System.IO;
Change
HttpResponseBase to TextWriter
I did this in three spots.
HttpResponseBase _response; to TextWriter _response;
public SIMForm(TextWriter response, string returnUrl, decimal amount,
string apiLogin, string transactionKey)
:this(response,returnUrl,amount,apiLogin,transactionKey,true){}
public SIMForm(TextWriter response, string returnUrl, decimal amount,
string apiLogin, string transactionKey, bool isTest) {
_response = response;
_amount = amount;
_apiLogin = apiLogin;
_transactionkey = transactionKey;
_returnUrl = returnUrl;
_isTest = isTest;
OpenForm();
}
Two more changes left
As directed in tpeczek answer, you need to change
helper.ViewContext.HttpContext.Response
to
helper.ViewContext.Writer
This will look like
public static SIMForm BeginSIMForm(this HtmlHelper helper, string returnUrl,
decimal amount, string apiLogin,
string transactionKey) {
return new SIMForm(helper.ViewContext.Writer,
returnUrl,amount,apiLogin,
transactionKey,true);}
public static SIMForm BeginSIMForm(this HtmlHelper helper, string returnUrl,
decimal amount, string apiLogin,
string transactionKey, bool isTest) {
return new SIMForm(helper.ViewContext.Writer,
returnUrl, amount, apiLogin,
transactionKey,isTest);}
This kind of problem usually happens when a helper which is writing directly to output stream was written for ASP.NET MVC 1 (and helpers that are enclosed in using are writing directly to output stream most of the time). In ASP.NET MVC 1 you could write to output stream by using this:
htmlHelper.ViewContext.HttpContext.Response.Output
In later ASP.NET MVC version you should be using this:
htmlHelper.ViewContext.Writer
That ensures Razor compatibility. If you have access to AuthorizeNet.Helpers source code you can fix it by yourself, if you don't than you have to contact authors for fixing it.
It's possible that the helper from AuthorizeNet is not written correctly to work with Razor. Without actually looking at the source of their assembly it's hard to say if that's the case. You might want to try to get in touch with their customer support.
Using the example from EpicThreeDev above I was able to get the form html to appear correctly. The Pay button however, was juxtaposed above the ccv field, so in order to fix that on the Index.cshtml code base I changed the HTML to
<br />
<input type = "submit" value = "Pay" style="position:relative; top:35px;" />
once I did that I was able to post the form, however after doing that I got the error that is addressed in post.
http://community.developer.authorize.net/t5/Integration-and-Testing/Having-Trouble-setting-up-MVC3-application-with-DPM/m-p/13226
Here's my solution. It just prints the Authorize.net hidden fields, so you can write your own form tag. Fill in your web.config with the relevant AppSettings values. This way you can easily change between development and production.
public static class MyAuthNetHelper
{
public const string TEST_URL = "https://test.authorize.net/gateway/transact.dll";
public const string LIVE_URL = "https://secure.authorize.net/gateway/transact.dll";
public static string ApiLogin
{
get { return ConfigurationManager.AppSettings["AuthNetAPILogin"]; }
}
public static string TransactionKey
{
get { return ConfigurationManager.AppSettings["AuthNetAPITransactionKey"]; }
}
public static string ReturnUrl
{
get { return ConfigurationManager.AppSettings["AuthNetReturnUrl"]; }
}
public static string ThanksUrl
{
get { return ConfigurationManager.AppSettings["AuthNetThanksUrl"]; }
}
public static bool TestMode
{
get { return bool.Parse(ConfigurationManager.AppSettings["AuthNetTestMode"]); }
}
public static string GatewayUrl
{
get { return TestMode ? TEST_URL : LIVE_URL; }
}
public static MvcHtmlString AuthNetDirectPostFields(this HtmlHelper helper, decimal amount)
{
var seq = Crypto.GenerateSequence();
var stamp = Crypto.GenerateTimestamp();
var fingerPrint = Crypto.GenerateFingerprint(TransactionKey,
ApiLogin, amount, seq.ToString(), stamp.ToString());
var str = new StringBuilder();
str.Append(helper.Hidden("x_fp_hash", fingerPrint));
str.Append(helper.Hidden("x_fp_sequence", seq));
str.Append(helper.Hidden("x_fp_timestamp", stamp));
str.Append(helper.Hidden("x_login", ApiLogin));
str.Append(helper.Hidden("x_amount", amount));
str.Append(helper.Hidden("x_relay_url", ReturnUrl));
str.Append(helper.Hidden("x_relay_response", "TRUE"));
return MvcHtmlString.Create(str.ToString());
}
}
cshtml:
<form id="paymentForm" method="POST" action="#MyAuthNetHelper.GatewayUrl" class="form-horizontal offset1">
#Html.AuthNetDirectPostFields(PutYourAmountHere)
...
</form>
ThanksUrl is used in your action to handle the response from Authorize.net. Check this for more: http://developer.authorize.net/integration/fifteenminutes/csharp/
I am trying to formulate a work-around for the lack of a "checkbox group" in ASP.NET MVC. The typical way to implement this is to have check boxes of the same name, each with the value it represents.
<input type="checkbox" name="n" value=1 />
<input type="checkbox" name="n" value=2 />
<input type="checkbox" name="n" value=3 />
When submitted, it will comma delimit all values to the request item "n".. so Request["n"] == "1,2,3" if all three are checked when submitted. In ASP.NET MVC, you can have a parameter of n as an array to accept this post.
public ActionResult ActionName( int[] n ) { ... }
All of the above works fine. The problem I have is that when validation fails, the check boxes are not restored to their checked state. Any suggestions.
Problem Code: (I started with the default asp.net mvc project)
Controller
public class HomeController : Controller
{
public ActionResult Index()
{ var t = getTestModel("First");
return View(t);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(TestModelView t)
{ if(String.IsNullOrEmpty( t.TextBoxValue))
ModelState.AddModelError("TextBoxValue", "TextBoxValue required.");
var newView = getTestModel("Next");
return View(newView);
}
private TestModelView getTestModel(string prefix)
{ var t = new TestModelView();
t.Checkboxes = new List<CheckboxInfo>()
{ new CheckboxInfo(){Text = prefix + "1", Value="1", IsChecked=false},
new CheckboxInfo(){Text = prefix + "2", Value="2", IsChecked=false}
};
return t;
}
}
public class TestModelView
{ public string TextBoxValue { get; set; }
public List<CheckboxInfo> Checkboxes { get; set; }
}
public class CheckboxInfo
{ public string Text { get; set; }
public string Value { get; set; }
public bool IsChecked { get; set; }
}
}
ASPX
<%
using( Html.BeginForm() ){
%> <p><%= Html.ValidationSummary() %></p>
<p><%= Html.TextBox("TextBoxValue")%></p>
<p><%
int i = 0;
foreach (var cb in Model.Checkboxes)
{ %>
<input type="checkbox" name="Checkboxes[<%=i%>]"
value="<%= Html.Encode(cb.Value) %>" <%=cb.IsChecked ? "checked=\"checked\"" : String.Empty %>
/><%= Html.Encode(cb.Text)%><br />
<% i++;
} %></p>
<p><input type="submit" value="submit" /></p>
<%
}
%>
Working Code
Controller
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(TestModelView t)
{
if(String.IsNullOrEmpty( t.TextBoxValue))
{ ModelState.AddModelError("TextBoxValue", "TextBoxValue required.");
return View(t);
}
var newView = getTestModel("Next");
return View(newView);
}
ASPX
int i = 0;
foreach (var cb in Model.Checkboxes)
{ %>
<input type="checkbox" name="Checkboxes[<%=i%>].IsChecked" <%=cb.IsChecked ? "checked=\"checked\"" : String.Empty %> value="true" />
<input type="hidden" name="Checkboxes[<%=i%>].IsChecked" value="false" />
<input type="hidden" name="Checkboxes[<%=i%>].Value" value="<%= cb.Value %>" />
<input type="hidden" name="Checkboxes[<%=i%>].Text" value="<%= cb.Text %>" />
<%= Html.Encode(cb.Text)%><br />
<% i++;
} %></p>
<p><input type="submit" value="submit" /></p>
Of course something similar could be done with Html Helpers, but this works.
I don't know how to solve your problem, but you could define your checkboxes with this code:
<%= Html.CheckBox("n[0]") %><%= Html.Hidden("n[0]",false) %>
<%= Html.CheckBox("n[1]") %><%= Html.Hidden("n[1]",false) %>
<%= Html.CheckBox("n[2]") %><%= Html.Hidden("n[2]",false) %>
Hidden fields are needed, because if checkbox is not checked, form doesn't send any value. With hidden field it sends false.
Your post method will be:
[HttpPost]
public ActionResult Test(bool[] n)
{
return View();
}
It may not be optimal and I am open to comments, but it works:)
EDIT
Extended version:
<%= Html.CheckBox("n[0].Checked") %><%= Html.Hidden("n[0].Value",32) %><%= Html.Hidden("n[0].Checked",false) %>
<%= Html.CheckBox("n[1].Checked") %><%= Html.Hidden("n[1].Value",55) %><%= Html.Hidden("n[1].Checked",false) %>
<%= Html.CheckBox("n[2].Checked") %><%= Html.Hidden("n[2].Value",76) %><%= Html.Hidden("n[2].Checked",false) %>
Your post method will be:
[HttpPost]
public ActionResult Test(CheckedValue[] n)
{
return View();
}
public class CheckedValue
{
public bool Checked { get; set; }
public bool Value { get; set; }
}
I wrote it without VS, so it may need little correction.
Behold the final solution:
public static class Helpers
{
public static string CheckboxGroup<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> propertySelector, int value) where TProperty: IEnumerable<int>
{
var groupName = GetPropertyName(propertySelector);
var modelValues = propertySelector.Compile().Invoke(htmlHelper.ViewData.Model);
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.Contains(value)))
{
builder.Attributes.Add("checked", null);
}
return builder.ToString(TagRenderMode.Normal);
}
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);
}
}
And in your view:
<%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "1")%>(iv),<br />
<%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "2")%>(vi),<br />
<%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "3")%>(vii),<br />
<%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "4")%>(ix)<br />
Well... the check boxes aren't going to know their state on their own, especially if you are not using the Html.CheckBox helper (if you are, see LuKLed's answer). You're going to have to put the checked state of each box in your ViewData (or Model) and then perform a look-up in your View in one way or another.
Warning: Really ugly proof-of-concept code:
Controller:
//validation fails
ViewData["checkboxn"] = n;
return View();
View:
<% int[] n = (int[])ViewData["checkboxn"]; %>
<input type="checkbox" name="n" value=1 <%= n != null && n.Contains(1) ? "checked=\"checked\"" : "" %> />
<input type="checkbox" name="n" value=2 <%= n != null && n.Contains(2) ? "checked=\"checked\"" : "" %> />
<input type="checkbox" name="n" value=3 <%= n != null && n.Contains(3) ? "checked=\"checked\"" : "" %> />
All I'm doing here is passing the array n back to the view, and if it contains a value for the respective checkbox, adding checked="checked" to the element.
You would probably want to refactor this into an HtmlHelper of your own, or otherwise make this less ugly, of course.
This solution may be of interest to those wanting a clean/simple approach:
Maintain state of a dynamic list of checkboxes in ASP.NET MVC
I wouldn't really recommend the use of Html.CheckBox unless you have a super simple, single checkbox bound to a single bool (or a couple of static ones at most). When you start having lists of checkboxes in a single array or dynamic checkboxes, it is difficult to work with and you end up programming the whole world in server side bloat just to deal with the shortfalls and get everything working. Forget it, and just use the clean HTML focused solution above and you're up and running quickly with less mess to maintain in the future.
I know this must be insanely late but just incase anyone else finds themselves here..
MVC does have a way to handle checkbox groups.
in your view model:
[Display(Name = "Which Credit Cards are Accepted:")]
public string[] EmployeeRoles{ get; set; }
On your Page:
<input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Supervisor"
#(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Supervisor") ? "checked=true" : string.Empty)/>
<span>Supervisor</span><br />
<input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Auditor"
#(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Auditor") ? "checked=true" : string.Empty)/>
<span>Auditor</span><br />
<input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Administrator"
#(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Administrator") ? "checked=true" : string.Empty) />
<span>Administrator</span>
I tried very hard to create these controls with razor but no dice. It keeps
creating that hidden field you all have referred to. for your checkbox group
you don't need that hidden field, just the code I have added above. You can create an html helper to create this code for you.
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);
}
on your page use it like so:
#Html.CheckboxGroup(m => m.EmployeeRoles, typeof(Enums.EmployeeRoles))
I use an enum but you can use any kind of collection