How to have ASP.Net MVC 3.0 Checkboxfor as checked by default? - asp.net-mvc-3

I want mt view to have the check box checked by default,
I tried something like this.
#Html.CheckBoxFor(model=>model.GenericsOK, new { id = ViewBag.GenericsOK, #checked = true })
and also
#Html.CheckBoxFor(model=>model.GenericsOK, new { id = ViewBag.GenericsOK, #checked = "checked"})
in both cased it give the below error.
String was not recognized as a valid Boolean.
My property is defined as this.
private bool _deafaultchecked = true;
[Display(Name = "Generics Ok")]
public bool GenericsOK
{
get { return _deafaultchecked; }
set { _deafaultchecked = value; }
}
any suggestions please?
Since i could not find a solution or this.
i got this done like this.
#Html.CheckBox("GenericsOK", true, new {id=ViewBag.GenericsOK, name="GenericsOK" })
this works for my requirement.
thanks for all who helped me.

In your controller's Create method (I presume), have you tried this?
public ActionResult Create()
{
return View(new YourModelClass { GenericsOk = true });
}

In the controller action where you create the model just set that field value to true.
For example
return View(new DriverCsvModel{SendEmails = true});
You should be using the state of the model, rather than forcing the UI into a checked state.

You will want to remove the #checked="checked" portion of the HTML attributes. If the viewmodel property is a boolean then it is unnecessary when you use the CheckBoxFor

In the default constructor for your model class, you can set the "GenericsOK" property to "True"

Related

How can I make ASP.NET MVC 3 render Html.CheckBoxFor and the corresponding hidden element with reversed values?

I'm using ASP.NET MVC3 with Razor.
I have a boolean value in my model which I would like to render as a check box in my view. However, I would like the check box to indicate the reverse of the boolean state. In other words, selecting the check box should set the bound model object to false, not true, when the form is submitted. And vice versa.
I can do this to set the value attribute on the rendered check box input element:
#Html.CheckBoxFor(model => model.MyBoolean, new { value = "false" })
But the hidden input element that is automatically created still has a value of false. Thus they both have a value of false, which means the bound model object is always set to false.
So how can I force the HTML helper to set the hidden element to true and the check box element to false?
I know that (a) I could alter the model and the database, (b) I could alter the values with javascript just prior to submission, and (c) I could swap whatever value is received in the controller after submission. I may do one of these, but I'm not asking for possible solutions; I'm asking whether it is possible to make the HTML helper do as I wish. I have searched extensively and haven't seen this addressed anywhere in official or unofficial sources. It seems like they should have a "swap" option or something.
class ViewModel {
public bool MyBoolean {get;set;}
public bool DisplayValue {
get {
return ! MyBoolean ;
}
set {
MyBoolean = !value;
}
}
}
And bind to the DisplayValue as it's setter updates you MyBoolean property anyway.
EDIT:
After reading your question again:.
You could use HtmlHelper to do that - but instead of using a CheckBox you could use a dropdown. The dropdown will define the "oppisite" values and text.
myModelInstance.PossibleValues = new[] { new SelectListItem { Value = "false", Text = "Not false" }, new SelectListItem { Value = "true", Text = "Not true" } };
Notice how the description is the opposite meaning of what you want the model to be. So for eg. for true you may have text as "Hidden" and false you may have the text as "Visible", true for "Disabled" and false for "Enabled" etc.
Then in your View:
#Html.DropDownList(Model.MyBoolean.ToString(), Model.PossibleValues)
The model will be updated with the correct value without have to do boolean toggles before viewing or updating.
For future readers, in my own opinion, HtmlHelpers are designed to render Html (as the name suggests). My preference for creating different way to render items is to create EditFor and DisplayFor templates. To make sure this is highly reusable, I also create model designed specifically for these templates. With your design, my models and templates might look like:
/Models/Controller/ControllerActionViewModel.cs
public class ControllerActionViewModel
{
public ControllerActionViewModel()
{
this.CheckboxBoolTemplate = new CheckboxBoolTemplate(false, true);
}
[Display(Name = "My Boolean")]
public SelectBoolTemplate MyBoolean { get; set; }
}
/TemplateModels/ControllerActionViewModel.cs
public sealed class SelectBoolTemplate
{
private bool _valuesSwapped = false;
private bool? _value;
private bool _defaultValue = false;
public SelectBoolTemplate()
{
}
public SelectBoolTemplate(bool valuesSwapped)
{
this._valuesSwapped = valuesSwapped)
}
public SelectBoolTemplate(bool defaultValue, bool valuesSwapped)
{
this._defaultValue = defaultValue;
this._valuesSwapped = valuesSwapped)
}
public bool Value
{
get
{
if (this._value.HasValue)
{
return this._value.Value
}
return this._defaultValue;
}
set
{
this._value = value;
}
}
}
/Views/Shared/EditorTemplates/SelectBoolTemplate.cshtml
#model SelectBoolTemplate
#{
string propertyName = ViewContext.ViewData.ModelMetadata.PropertyName;
string fullPropertyName = ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix;
string labelText = ViewContext.ViewData.ModelMetadata.DisplayName
?? ViewContext.ViewData.ModelMetadata.PropertyName;
}
#Html.LabelForModel()
#Html.Checkbox(fullPropertyName, Model.Value)
I know this is too late for the original query but for anyone reading in future there's an alternative way to handle checkboxes with reversed false/true for checked/unchecked which requires no changes to the model - create a checkbox for false and a hidden field for true
<input id="#Html.IdFor(model => model.BoolProperty)" name="#Html.NameFor(model => model.BoolProperty)" type="checkbox" value="false" #(Model.BoolProperty? "" : "checked=\"checked\"" ) />
<input name="#Html.NameFor(model => model.BoolProperty)" type="hidden" value="true" />

MVC 3 How to tell what view a controller action is being called from-

Is there a way to tell what view a controller action is being called from?
For example, I would like to use "ControllerContext.HttpContext.Request.PhysicalPath" but it returns the path in which the controller action itself is located:
public ActionResult HandleCreateCustomer()
{
// Set up the customer
//..code here to setup the customer
//Check to see of the calling view is the BillingShipping view
if(ControllerContext.HttpContext.Request.PhysicalPath.Equals("~/Order/BillingShipping"))
{
//
return RedirectToAction("OrderReview", "Order", new { id = customerId });
}
else
{
return RedirectToAction("Index", "Home", new { id = customerId });
}
}
If you have a fixed number of locations that it could possibly be called from, you could create an enum where each of the values would correspond to a place where it could have been called from. You'd then just need to pass this enum value into HandleCreateCustomer, and do your condition statement(s) based on that.
At the moment I am using something of the sort:
In the View I am populating a TempData variable using:
#{TempData["ViewPath"] = #Html.ViewVirtualPath()}
The HtmlHelper method ViewVirtualPath() is found in the System.Web.Mvc.Html namespace (as usual) and is as follows and returns a string representing the View's virtual path:
public static string ViewVirtualPath(this HtmlHelper htmlHelper)
{
try{
return ((System.Web.WebPages.WebPageBase)(htmlHelper.ViewDataContainer)).VirtualPath;
}catch(Exception){
return "";
}
}
I will then obviously read the TempData variable in the controller.
I found another way.
In the controller you want to know what page it was called from.
I added the following in my controller
ViewBag.ReturnUrl = Request.UrlReferrer.AbsolutePath;
Then in the View I have a 'Back' button
#(Html.Kendo().Button().Name("ReturnButton")
.Content("Back to List").Events(e => e.Click("onReturn"))
.HtmlAttributes(new { type = "k-button" })
)
Then the javascript for the onReturn handler
function onReturn(e) {
var url = '#(ViewBag.ReturnUrl)';
window.location.href = url;
}

How to detect in code if property is decorated with HiddenInput

I have a view where I need to detect if a property is decorated with hidden input.
My property is defined as:
[HiddenInput(DisplayValue = false)]
public string UserName{ get; set; }
My attempt so far has been:
var column.Member = "UserName";
if (ViewData.ModelMetadata.HideSurroundingHtml == true &&
ViewData.Values.Contains(column.Member))
{
column.Visible = false;
}
I have read that I might be able to use "HideSurroundingHtml" to determine if the property should not be displayed.
Any ideas how to detect this?
You can use reflection to see if a specific property has an attribute.
Look at this question.
In the various answers a user also posted a snippet to create an extension method to check if a property has a specific attribute or not. Hope it helps
My solution to this problem is as follows:
I have created html helper that gives me array of names with properties that has been decorated with the "HiddenInput" attribute.
public static string[] GetListOfHiddenPropertiesFor<T>(this HtmlHelper htmlHelper)
{
Type t = typeof(T);
var propertyInfos = t.GetProperties()
.Where(x => Attribute.IsDefined(x, typeof(HiddenInputAttribute)))
.Select(x => x.Name).ToArray();
return propertyInfos;
}
this is all i needed

Validate checkbox on the client with FluentValidation/MVC 3

I am trying to validate if a check box is checked on the client using FluentValidation. I can't figure it our for the life of me.
Can it be done using unobtrusive validation?
Let's assume that you have the following model:
[Validator(typeof(MyViewModelValidator))]
public class MyViewModel
{
public bool IsChecked { get; set; }
}
with the following validator:
public class MyViewModelValidator : AbstractValidator<MyViewModel>
{
public MyViewModelValidator()
{
RuleFor(x => x.IsChecked).Equal(true).WithMessage("Please check this checkbox");
}
}
and a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
with a corresponding view:
#model MyViewModel
#using (Html.BeginForm())
{
#Html.LabelFor(x => x.IsChecked)
#Html.CheckBoxFor(x => x.IsChecked)
#Html.ValidationMessageFor(x => x.IsChecked)
<button type="submit">OK</button>
}
and in Global.asax you have registered the fluent validation model validator provider:
FluentValidationModelValidatorProvider.Configure();
So far we have server side validation up and running fine. That's good. That's always the first part that we must setup. I have seen people focusing too much on doing client side validation that they forget doing server side validation and when you disable javascript (or even worse if you stumble upon a user with bad intentions), well, bad things happen.
So far we are confident because we know that even if something gets screwed up on the client our domain is protected with server side validation.
So let's now take care for the client validation. Out of the box FluentValidation.NET supports automatic client validation for the EqualTo validator but when comparing against another property value which is the equivalent of the [Compare] data annotation.
But in our case we are comparing against a fixed value. So we don't get client side vaildation out of the box. And when we don't get something out of the box, we need to put it in the box.
So we start by defining a custom FluentValidationPropertyValidator:
public class EqualToValueFluentValidationPropertyValidator : FluentValidationPropertyValidator
{
public EqualToValueFluentValidationPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator)
: base(metadata, controllerContext, rule, validator)
{
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
if (!this.ShouldGenerateClientSideRules())
{
yield break;
}
var validator = (EqualValidator)Validator;
var errorMessage = new MessageFormatter()
.AppendPropertyName(Rule.GetDisplayName())
.AppendArgument("ValueToCompare", validator.ValueToCompare)
.BuildMessage(validator.ErrorMessageSource.GetString());
var rule = new ModelClientValidationRule();
rule.ErrorMessage = errorMessage;
rule.ValidationType = "equaltovalue";
rule.ValidationParameters["valuetocompare"] = validator.ValueToCompare;
yield return rule;
}
}
that we are going to register in Application_Start:
FluentValidationModelValidatorProvider.Configure(provider =>
{
provider.AddImplicitRequiredValidator = false;
provider.Add(typeof(EqualValidator), (metadata, context, description, validator) => new EqualToValueFluentValidationPropertyValidator(metadata, context, description, validator));
});
So far we have associated our custom FluentValidationPropertyValidator with the EqualValidator.
The last part is to write a custom adapter:
(function ($) {
$.validator.unobtrusive.adapters.add('equaltovalue', ['valuetocompare'], function (options) {
options.rules['equaltovalue'] = options.params;
if (options.message != null) {
options.messages['equaltovalue'] = options.message;
}
});
$.validator.addMethod('equaltovalue', function (value, element, params) {
if ($(element).is(':checkbox')) {
if ($(element).is(':checked')) {
return value.toLowerCase() === 'true';
} else {
return value.toLowerCase() === 'false';
}
}
return params.valuetocompare.toLowerCase() === value.toLowerCase();
});
})(jQuery);
And that's pretty much it. All that's left is to include the client scripts:
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/customadapter.js")" type="text/javascript"></script>
I like the Darin Dimitrov's answer, but if you want to do it quickly, here is my alternative way.
Create an additional property in your model, e.g.:
public bool ValidationTrue { get; set; }
and set its value to true in the model's contructor.
Use it in your view to save the value across the requests:
#Html.HiddenFor(x => x.ValidationTrue)
Now add a validation rule like this:
public class MyViewModelValidator : AbstractValidator<MyViewModel>
{
public MyViewModelValidator()
{
RuleFor(x => x.ValidationTrue)
.Equal(true); // check it for security reasons, if someone has edited it in the source of the page
RuleFor(x => x.HasToBeChecked)
.Equal(x => x.ValidationTrue) // HasToBeChecked has to have the same value as ValidationTrue (which is always true)
.WithMessage("Required");
}
}
That validation is supported by the unobtrusive validator out-of-the-box.
I am coding in ASP.NET MVC5 and Darin's code produces a javascript error on the lines that reference value.ToLowerCase() when a checkbox is involved. Another issue is that this code invalidates the client side equality comparison between two properties. It only seems to work when comparing against a literal value...That may have been his intent, but I need it to work for both situations:
Here's one possible workaround, that involves only two changes to Darin's answer:
First, I updated the javascript function with the following.
$.validator.addMethod('equaltovalue', function (value, element, params) {
if ($(element).is(':checkbox')) {
value = $(element).is(':checked') ? "true" : "false";
}
return params.valuetocompare.toLowerCase() === value.toLowerCase();
});
Secondly, I updated EqualToValueFluentValidationPropertyValidator with the following:
public class EqualToValueFluentValidationPropertyValidator : FluentValidationPropertyValidator
{
EqualValidator EqualValidator
{
get { return (EqualValidator)Validator; }
}
public EqualToValueFluentValidationPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator) : base(metadata, controllerContext, rule, validator) {
ShouldValidate = false;
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() {
if (!ShouldGenerateClientSideRules()) yield break;
var propertyToCompare = EqualValidator.MemberToCompare as PropertyInfo;
if(propertyToCompare != null) {
// If propertyToCompare is not null then we're comparing to another property.
// If propertyToCompare is null then we're either comparing against a literal value, a field or a method call.
// We only care about property comparisons in this case.
var comparisonDisplayName =
ValidatorOptions.DisplayNameResolver(Rule.TypeToValidate, propertyToCompare, null)
?? propertyToCompare.Name.SplitPascalCase();
var formatter = new MessageFormatter()
.AppendPropertyName(Rule.GetDisplayName())
.AppendArgument("ComparisonValue", comparisonDisplayName);
string message = formatter.BuildMessage(EqualValidator.ErrorMessageSource.GetString());
yield return new ModelClientValidationEqualToRule(message, CompareAttribute.FormatPropertyForClientValidation(propertyToCompare.Name)) ;
}
else
{
var validator = (EqualValidator)Validator;
var errorMessage = new MessageFormatter()
.AppendPropertyName(Rule.GetDisplayName())
.AppendArgument("ValueToCompare", validator.ValueToCompare)
.BuildMessage(validator.ErrorMessageSource.GetString());
var rule = new ModelClientValidationRule();
rule.ErrorMessage = errorMessage;
rule.ValidationType = "equaltovalue";
rule.ValidationParameters["valuetocompare"] = validator.ValueToCompare;
yield return rule;
}
}
}
This code was copied from the EqualToFluentValidationPropertyValidator internal class in the fluentvalidation source, and I added Darin's logic after the else. This allows the client-side validation to work for property comparisons as well as value comparisons...I'm not sure if this is a great approach since you're basically overriding the built-in equality validator and it may break in future releases of fluent validation....but Darin's answer has the same issue.
There might be better ways to handle this. If somebody knows of a way to directly include the logic from the internal EqualToFluentValidationPropertyValidator class, then I'd love to hear it.
it's based on #cryss answer
RuleFor(x => x.HasToBeChecked)
.Equal(x => true)
.WithMessage("Required");
you don't need to use additional property

How to pass class via RedirectToAction

I have the following code:
public ActionResult Index()
{
AdminPreRegUploadModel model = new AdminPreRegUploadModel()
{
SuccessCount = successAddedCount,
FailureCount = failedAddedCount,
AddedFailure = addedFailure,
AddedSuccess = addedSuccess
};
return RedirectToAction("PreRegExceUpload", new { model = model });
}
public ActionResult PreRegExceUpload(AdminPreRegUploadModel model)
{
return View(model);
}
but model is null when I breakpoint on PreRegExcelUpload. Why?
Instead of using the Session object in Evgeny Levin's answer I would suggest to use TempData. See http://rachelappel.com/when-to-use-viewbag-viewdata-or-tempdata-in-asp.net-mvc-3-applications about TempData.
You could also fix this by calling return PreRegExceUpload(model); instead of return RedirectToAction(..) in you Index function.
TempData is just a "smart" wrapper for the Session, under the hood it still acts the same way.
Since it's only 4 fields, i would pass them via querystring.
Always try and avoid session/tempdata where possible, for which in this scenario it certainly is.
Are you sure that's your full code? As it doesn't make sense.
If your POST'ing some data and saving it to the database (for example), usually you redirect to another action passing the unique identifier (which is usually generated after the save), fetch it back from the DB and return the view.
That is much better practice.
If you explain your scenario a bit more, and show the proper code your using, i can help further.
Use session to pass model to method:
public ActionResult Index()
{
AdminPreRegUploadModel model = new AdminPreRegUploadModel()
{
SuccessCount = successAddedCount,
FailureCount = failedAddedCount,
AddedFailure = addedFailure,
AddedSuccess = addedSuccess
};
Session["someKey"] = model;
return RedirectToAction("PreRegExceUpload");
}
public ActionResult PreRegExceUpload()
{
var model = (AdminPreRegUploadModel) Session["someKey"];
Session["someKey"] = null;
return View(model);
}
Method RedirectToAction() can't take non primitive types as parameters, because url parameters is string.

Resources