Convert Y/N values of razor html checkbox in MVC - asp.net-mvc

Im reading a Y/N value from my model in a razor for loop.
I want to change the value from Y/N to true/false.
<td>#Html.CheckBoxFor(modelItem => (item.ReqDowngrade == "Y" ? true : false))</td>
I keep geting this error: System.InvalidOperationException: 'Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.'
Is there any way I can do this without creating a server view model?

This declaration is totally wrong:
#Html.CheckBoxFor(modelItem => (item.ReqDowngrade == "Y" ? true : false))
CheckBoxFor helper only accepts viewmodel properties with either bool or Nullable<bool> type for model binding, hence the conditional expression above should not be used. If you want to assign Y or N value to a new bool viewmodel property bound with CheckBoxFor, do this instead:
Viewmodel
// assumed both 'ReqDownGrade' & new bool property are in same viewmodel class
public bool CheckReqDownGrade
{
get
{
// returns false if ReqDownGrade is 'N'
return (ReqDownGrade == "Y");
}
set
{
CheckReqDownGrade = value;
CheckReqDownGrade == true ? ReqDownGrade = "Y" : ReqDownGrade = "N";
}
}
View
#Html.CheckBoxFor(model => model.CheckReqDownGrade)
If you still insist to not adding bool viewmodel property, you can use a HiddenFor, standard HTML input element with type="checkbox" attribute and simple JS trick:
View
#Html.HiddenFor(modelItem => item.ReqDowngrade, new { id = "ReqDownGrade" })
<input id="CheckReqDownGrade" type="checkbox" #(item.ReqDowngrade == "Y" ? "checked='checked'" : "") />
JS (jQuery)
<script>
$(function() {
$('#CheckReqDownGrade').click(function() {
var isChecked = $(this).is(':checked');
$('#ReqDownGrade').val(isChecked ? 'Y' : 'N');
});
});
</script>

Related

Thymeleaf, how to delcare default values for variables?

For example,
sortDir field is passed to model, but if I forget it, I want to use asc as default one.
This does not work as it shows div only when sortDir==null.
<div class="wrapper"
th:if="${sortDir == null}" th:with="sortDir=${'asc'}">
// Main content
</div>
You should remove your conditional on the div and try to decide on the value with an inline expression as follows:
<div class="wrapper"
th:with="sortDir=${sortDir != null} ? sortDir : 'asc'">
// Main content
</div>
Another way to achieve this is by setting the value right in the controller before you return from the controller method. An example line might be as follows:
#GetMapping
public String getSomething(Model model) {
if (sortDir == null) { sortDir = "asc" };
model.addAttribute("sortDir", sortDir);
return "someView";
}

ASP.Net MVC Dynamic input bound to same controller property

I have 2 controller fields say Type and Data.
Depending on value selected for Type (Date or Text), I want to display Data field dynamically as either a text input or a custom timepicker input.
Since only one will be rendered at any time, I need to bind with the same property name (Data).
This is what I am trying:
#if (Model.Type == "Date")
{
// custom timepicker control goes here
<input asp-for="Data" class="form-control timepicker"/>
}
else
{
<input asp-for="Data" class="form-control text-input" type="text"/>
}
On page load only text input is rendered, and it shows/hides based on Type selected. The timepicker input is never displayed (the html is not generated at all).
Is there a way to achieve this in MVC?
You can not have two <input> elements with the same name. If a <form> containing multiple inputs with the same name is posted, the MVC model binder will only bind one value from the last input.
To achieve what you want, you have two options:
Either have only one input with name="Data" of type="text" in the View, and let the timepicker write the time as a string to this input. Then in the controller, parse this input value depending on the selected Type.
Or have two inputs with name="TextData" and name="TimeData", and disable and hide one of these inputs using JS depending on the selected Type. In the controller, read the value from the right input depending on the selected Type. This is arguably the cleaner solution.
In MVC5 the second solution would look like this (I am not familiar with MVC-Core):
#model MyViewModel
#using (Html.BeginForm("Submit", "MyController", FormMethod.Post)) {
#Html.EditorFor(m => m.Type)
#Html.EditorFor(m => m.TextData, new { #class = "text-input"})
#Html.EditorFor(m => m.TimeData, new { #class = "timepicker"})
}
<script type="text/javascript">
function toggleInput_() {
if ($('##Html.IdFor(m => m.Type)').val() === 'Text') {
$('##Html.IdFor(m => m.TextData)').prop('disabled', false).show();
$('##Html.IdFor(m => m.TimeData)').prop('disabled', true).hide();
}
else {
$('##Html.IdFor(m => m.TextData)').prop('disabled', true).hide();
$('##Html.IdFor(m => m.TimeData)').prop('disabled', false).show();
}
}
$(document).ready(function() {
$('##Html.IdFor(m => m.Type)').on('change', function() {
toggleInput_(); // toggle when drop down changes
});
toggleInput_(); // toggle initially on page load
});
</script>
Controller:
[HttPost]
public ActionResult Submit(MyViewModel postData) {
string textValue = null;
DateTime? timeValue = null;
if (postData.Type == "Text") {
textValue = postData.TextData;
}
else {
timeValue = postData.TimeData;
}
// ...
}
ASP MVC already has this functionality built in with Editor Templates. By following the convention, you can specify a template to be used for any type (including user-defined complex types) which will be rendered with #Html.EditorFor().
In a nutshell, just place two partial views in your ~/Views/Shared/EditorTemplatesfolder, one with model type DateTime and the other string. The correct partial view will be rendered when using #Html.EditorFor(m => m.Property) based on the type of Property.
Note: the default editor for a string property will already be an input with type="text", so you don't necessarily need to specify that template.
See this link for a tutorial on Editor templates (and Display templates):
https://exceptionnotfound.net/asp-net-mvc-demystified-display-and-editor-templates/

Pass in #(Model.newsletterOptin ? true : false) value into checked key inside a dictionary for htmlhelper

I am trying to replace some html with html helpers and I am trying to pass a dictionary of HTMLAttributes into the CheckboxFor helper method. My problem is that I do not know how to get this expression to work as an object param for my instantiation of the dictionary for the id checked. The html looks like this
<input type="checkbox"
id="newsletterOptin"
name="newsletterOptin"
checked="#(Model.newsletterOptin ? true : false)" />
and the helper looks like this
#Html.CheckBoxFor(m => m.newsletterOptin, new Dictionary<string, object>() {
{ "id", "newsletterOptin" },
{ "checked", "#(Model.newsletterOptin ? true : false)" }
})
How can I pass the #(Model.newsletterOptin ? true : false) so that it is used properly?
Your helper starts with an # sign, which starts a code block in ASP.NET Razor. You don't need to use # again, because you can write it like any other plain C# code:
#Html.CheckBoxFor(m => m.newsletterOptin, new Dictionary<string, object> {
{ "id", "newsletterOptin" },
{ "checked", Model.newsletterOptin ? "true" : "false" }
})

Ext.Net MVC - Render partial view with parameter

I have a partial view on my mvc page. The view is rendered by default with no data, but will be updated based on a value selection from a combobox in another section of the page. The partial view takes an id as a parameter which it will use to get the data needed to return the model.
The problem that I am having is that on the initial load, the parameter is null since nothing has been selected and I am getting a null value exception.
Is there a way that I can use an if statement in a direct events call to check the selected item and return 0 is that is null?
See me sample code below for clarification.
Thanks
Here are the relevant parts of my main page (index.cshtml) -
x.ComboBox()
.ID("MyCombo")
.DisplayField("Title")
.ValueField("Number")
.TypeAhead(false)
.Width(500)
.PageSize(10)
.HideBaseTrigger(true)
.MinChars(0)
.TriggerAction(TriggerAction.Query)
.DirectEvents(de =>
{
de.Select.Url = Url.Action("MyPartial");
#* Can I use an if statment here to check the selected item's value? *#
de.Select.ExtraParams.Add(new { id = App.MyCombo.getValue() });
})
.ListConfig(Html.X().BoundList()
.LoadingText("Searching...")
.ItemTpl(Html.X().XTemplate()
.Html(#<text>
<div class="search-item">
<h3><span>{Number}</span>{Title}</h3>
{Description}
</div>
</text>)
)
)
........
#Html.Partial("MyPartial", Model.MyPartialVM)
and here is my controller code -
public ActionResult MyPartial(string id)
{
var vm = new MyPartialViewModel
{
Number = id,
Title = "New Title"
};
ViewData.Model = vm;
var pvr = new Ext.Net.MVC.PartialViewResult
{
ViewData = this.ViewData
};
return pvr;
}
This works if I hardcode a parameter value, but not if I try it as it is now. Here is the error I get -
Message=Cannot perform runtime binding on a null reference
So I was thinking that I can do an if in teh DirectEvents piece to check for a null on the combobox selection, I can inject a 0 when necessary and handle that in the controller. Can this be done?
Try if this works:
x.ComboBox()
.ID("MyCombo")
.DisplayField("Title")
.ValueField("Number")
.TypeAhead(false)
.Width(500)
.PageSize(10)
.HideBaseTrigger(true)
.MinChars(0)
.TriggerAction(TriggerAction.Query)
.DirectEvents(de =>
{
de.Select.Url = Url.Action("MyPartial");
de.Select.ExtraParams.Add(new {
Name = "id",
Value ="App.MyCombo.getValue() == null ? '0' : App.MyCombo.getValue()",
Mode = ParameterMode.Raw
});
})
.ListConfig(Html.X().BoundList()
.LoadingText("Searching...")
.ItemTpl(Html.X().XTemplate()
.Html(#<text>
<div class="search-item">
<h3><span>{Number}</span>{Title}</h3>
{Description}
</div>
</text>)
)
)

How to bind checkbox to a string property in asp net mvc

I had in my classes some fields that represents true or false, but it has string values "T" or "F".
How to bind the checkbox to these fields?
You can do this in ASP.Net MVC Razor
<input type="checkbox" name="someName" value="#Model.SomeValue"
#(Model.IsChecked == "T" ? "checked='checked'" : "") />
However, this may not be what you are looking for, since you would have to do some manual work on the server to figure out values that had been "unchecked".
By default only your checked values will get sent to the server.
UPDATE:
The Html.CheckBox and Html.CheckBoxFor helper methods both emit hidden fields in order to make sure everything binds correctly back to your model. You can imitate this behavior pretty easily.
First you need to emit a hidden field that will be bound to your model on the server.
#Html.HiddenFor(model => model.StringBool, new { id = "_stringBool" })
Next you create a plain jane checkbox and set the initial state to reflect your model.
<input type="checkbox" id="myCheckBox" #(Model.StringBool == "T" ? "checked='checked'" : "") />
This checkbox's only purpose is to proxy values to and from the hidden field so your model will automatically get bound on the server. This can be achieved with some simple jQuery.
$("#myCheckBox").click(function () {
var isChecked = $(this).is(":checked");
$("#_stringBool").val(isChecked ? "T" : "F");
});
Now checking and unchecking the box will set the value of your bound hidden field accordingly. When you post to the server your values will be preserved via model binding.
Some things to note
This does not take into account validation. It is very easy to change the value of the hidden field so make sure you properly validate on the server side!
When you set the checkstate of the new checkbox items, just put an if statement:
checkBox1.Checked = (stringValue == "T") ? true : false;
I made my own extension to solve this problem. It is a little tidyer in the razorview, helps minimizing the c# / razor mixture. Here's the class:
public static class CheckBoxExtensions {
public static MvcHtmlString ValueCheckbox<TModel>(this HtmlHelper<TModel> htmlHelper, string name, string value, bool isChecked, IDictionary<string, object> htmlAttributes, bool disabled = false)
{
string result = string.Format(CultureInfo.InvariantCulture,
"<input type=\"checkbox\" name=\"{0}\" value=\"{1}\" {2} {3} ",
name, value, (isChecked) ? "checked=\"checked\"" : "", (disabled) ? "disabled=\"disabled\"" : "");
if (htmlAttributes != null && htmlAttributes.Count > 0)
{
foreach (KeyValuePair<string, object> item in htmlAttributes)
{
result += string.Format(CultureInfo.InvariantCulture, "{0}=\"{1}\" ", item.Key, item.Value.ToString());
}
}
result += " />";
return new MvcHtmlString(result);
}
}
And this is what I do in the razorview:
Html.ValueCheckbox("SelectedItems",
item.Number,
(Model.SelectedItems.Contains(item.Number)),
new Dictionary<string, object>() {
{ "data-disable-bubble", "true" },
{ "data-forms-enable-any-checked-checkbox", "true" }
}
)
Dont mind the weir HtmlAttributes, I figured I would just let them in there :-)

Resources