ASP.Net MVC Dynamic input bound to same controller property - asp.net-mvc

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/

Related

kendo radio button value

I've following code in razor view. How do I use Kendo Radio button to render the same? Mainly, I'm struggling to assign enum value to radio button value.
#if (Model == declaredEnum.​Val1)
{
#Html.RadioButtonFor(l => l, (int)declaredEnum.​Val1, new { #checked = "checked" });
}
else
{
#Html.RadioButtonFor(l => l, (int)declaredEnum.​Val1);
}
#Html.LabelFor(l => l, "Label")​
Edit
Definition of Enum
Public Enum declaredEnum
{
Val1,
Val2
}
There is another radio button with the same code, but it checks for val2. Current logic is working fine. I just need to convert to Kendo control instead of razor.
I realize that this post is very old, but I am working with Kendo UI for the first time and needed to figure this out for myself. The following code snippet creates a radio button group called "name-of-radio-group" from an enum with two values. It defaults the first radio button to checked:
<div class="form-group row">
#Html.Label(Enum.GetNames(typeof(declaredEnum)).ToList()[0], new { #class = "col-sm-2" })
#(Html.Kendo().RadioButtonFor(m => m.declaredEnum).Checked(true).Name(Enum.GetNames(typeof(declaredEnum)).ToList()[0])
.HtmlAttributes(new { #class = "col-sm-1", name = "name-of-radio-group"}))
#Html.Label(Enum.GetNames(typeof(declaredEnum)).ToList()[1], new { #class = "col-sm-2"})
#(Html.Kendo().RadioButtonFor(m => m.declaredEnum).Name(Enum.GetNames(typeof(declaredEnum)).ToList()[1])
.HtmlAttributes(new {#class = "col-sm-1", name = "name-of-radio-group"})
)
</div>
In my example I only had two enum values so I did not feel the need to use a loop, instead I just indexed the enums directly. In case it is not clear to someone the m.declaredEnum represents a property on a strongly typed model where the property name is the same as the name of the enum.

How to preselect radio-buttons with EditorTemplate in MVC?

I am developing an edit form. The form i need to create needs to be dynamic so i went down the road of using EditorForModel and have many different but similar models in behind. To customize each field, i use EditorTemplates for control like dropdowns, checkboxes and radiobuttons. The project needs to be delivered soon and i have done almost everything but stuck with few things.
Here is my Sex.cshmt as EditorTemplate
#Html.RadioButton("", "M") Male
#Html.RadioButton("", "F") Female
The Edit view doesn't have much as well.
#using (Html.BeginForm("Edit", "Editor", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(m => m.Id)
#Html.EditorForModel()
<input type="submit" class="btn btn-default" value="Save" />
}
And i got a model with few properties. Very simple. Field for Sex has UIHint annotation so that it can pick up Sex editor template. And there are some Required annotation for some properties as well. These work fine.
And i got my controller action to return right type of person and return a view using a Factory. Just a standard factory with a switch statement that return right object.
public ActionResult Edit(int p)
{
var person= _service.personService.Get(p);
var canFac = new CandidateFactory(type);
var res = canFac.CreateObject(person);
return PartialView("_Edit", res);
}
In the above code, res is an dynamically created object with properties. It has a property for Sex and it's a string with value of 'M' or 'F'. I know naturally radio buttons are bools but i have to map M or F to the radio buttons.
The form was generated fine. All the normal text-boxes are populated with data. But others like Radio buttons and check-boxes aren't populated. So, my question is, In my scenario, how do i pre-populate or pre-select radio-buttons with data?
You should make use of the html attributes:
#Html.RadioButton("M","M", Model == "M" ? new { Checked = "checked" } : null) Male
#Html.RadioButton("F","F,", Model == "F" ? new { Checked = "checked" } : null) Female

getting string values as well in textbox while using Html.TextBoxFor

In my partial view I have passed some list of strings from a method in controller
Here is my partial view
#model IEnumerable<string>
#foreach(var names in Model)
{
<div class="input-block-level">#Html.TextBoxFor(m=>names)</div>
<br/>
}
Here is how it looks in browser
Why am I getting the texts in textbox?
I mean I would want them there but as placeholder not default text.
How can I not have those values and just have a plane textbox?
Use this to change initial value:
#Html.TextBoxFor(m => names, new { Value = "" })

Selected property is ignored in MVC using DropList or DropListFor

I have an enum, which is a mapping for a description of a property against an index in the database. I have a property on my ViewModel that represents an instance of that enum. I've tried both returning a list of enum instances, which means I do this:
#Html.DropDownListFor(m => m.CurrentFilter,
Model.FilterTypes.Select(entry =>
new SelectListItem{ Text = entry.ToString(), Value = ((int)entry).ToString()}),
new { #class = "normalcell", style = "WIDTH: 132px;" })
and returning a list of SelectListItems, which means I do this:
#Html.DropDownListFor(m => m.CurrentFilter,
Model.FilterTypes.Select(entry =>
new SelectListItem{ Text = entry.Text, Value = entry.Value, Selected = entry.Selected}),
new { #class = "normalcell", style = "WIDTH: 132px;" })
In the second case, when I debug, I am certain that the Selected property on the entry object is true for the correct item. In both cases, there is no 'selected' attribute written in to my HTML and so the correct item is not selected. I've also set a breakpoint, and CurrentFilter DOES have the correct value and the rest of my page renders appropriately, so it's finding the value.
I've written plenty of drop lists that work, using similar code, I can't for the life of me see why this does not work, no matter how I try to do it ?
I have also tried:
#Html.DropDownListFor(m => m.CurrentFilter,
Model.FilterTypes,
new { #class = "normalcell", style = "WIDTH: 132px;" })
which seems to me to be the logical way to do it ( return a list of SelectListItems and just do no processing in the page ), but the Selected property is still ignored.
Update:
I tried to do it this way:
#Html.DropDownList("CurrentFilter", Model.FilterTypes, new { #class = "normalcell", style = "WIDTH: 132px;" })
and just read the value out of the request. It's still the case that I am returning a list with only one item that has Selected == true, and it's still the case that MVC is ignoring it.
This works, not surprisingly, but I'd love to know why all the other things don't.
<select class="normalcell" id="CurrentFilter" name="CurrentFilter" style="WIDTH: 132px;">
#foreach (SelectListItem item in Model.FilterTypes)
{
if (item.Selected)
{
<option value="#item.Value" selected="selected">#item.Text</option>
}
else
{
<option value="#item.Value">#item.Text</option>
}
}
I believe the reason is that the MVC binding engine doesn't know how to deal with Enum values. I think you need to create a "proxy" property for your view model. Something like this...
public enum MyEnum { a, b, c, d };
public MyEnum EnumVal { get; private set; }
public string EnumProxy
{
get { return EnumVal.ToString(); }
set { EnumVal = (MyEnum)Enum.Parse(typeof(MyEnum), value); }
}
Then construct the drop-down list using the Enum names:
Type t = typeof(MyEnum);
var ddList = Enum.GetNames(t).Select(
item => new SelectListItem() { Text = item, Value = item }
).ToArray();
Now you should be able to use DropDownListFor normally:
#Html.DropDownListFor(model => model.EnumProxy, ddList)
I'm not sure if there's a neater solution. This one should work though.
My DDL tutorial shows how to use enums. See See my tutorial Working with the DropDownList Box and jQuery and My blog Cascading DropDownList in ASP.Net MVC Part 2 of the tutorial explains: When the string argument (the property to bind) and the SelectList object have the same name, the selected value is not used.
Darin has a SO post on another common reason the selected value is not display. See MVC DropDownList SelectedValue not displaying correctly

How to render HtmlAttributes with object values using ASP.NET MVC 3 Razor?

I am trying to render the following HTML using an MVC3 Razor View:
<input id="EffectiveDate" name="EffectiveDate" type="date" data-options='{"mode": "flipbox"}' />
I have been unable to get the quotation marks in the data-options attribute to render. No matter what I try, they are rendered as "
Here are a couple of the many approaches I have tried in my View:
#Html.TextBoxFor(model => model.EffectiveDate, new { type = "date", data_options= " { 'mode':'flipbox' }"})
and
#Html.TextBoxFor(model => model.EffectiveDate, new { type = "date", data_options= #Html.Raw("{\"mode\":\"flipbox\"}")})
Any suggestions on how to decode the quotation marks?
You can do this by creating an MVC Editor template. First, create a folder called "EditorTemplates" inside the "Views\Shared" folder. Then put a file called DateTime.cshtml inside the EditorTemplates folder.
Then you can simply use the EditorFor() method against your view model's property like this (provided that the EffectiveDate property of of type DateTime):
#Html.EditorFor(m => m.EffectiveDate)
The complete code for the DateTime.cshtml editor template looks like this:
#model System.DateTime
#{
var id = this.ViewData.TemplateInfo.GetFullHtmlFieldId("");
var name = this.ViewData.TemplateInfo.GetFullHtmlFieldName("");
}
<input id="#id" name="#name" type="date" data-options='{"mode": "flipbox"}' />
This will produce the exact output that you are seeking.
One thing is certain: special symbols will always be encoded when you use any of the default MVC input extensions (i.e. TextBoxFor). That is because TagBuilder itself, which is used to build the tags for the HtmlHelper extensions, HtmlEncodes each attribute value in a tag. You can see this in the TagBuilder source:
private void AppendAttributes(StringBuilder sb)
{
foreach (var attribute in Attributes)
{
string key = attribute.Key;
if (String.Equals(key, "id", StringComparison.Ordinal /* case-sensitive */) && String.IsNullOrEmpty(attribute.Value))
{
continue; // DevDiv Bugs #227595: don't output empty IDs
}
string value = HttpUtility.HtmlAttributeEncode(attribute.Value);
sb.Append(' ')
.Append(key)
.Append("=\"")
.Append(value)
.Append('"');
}
}
Since you have no way to send that value already decoded, you have to decode it yourself in JavaScript. Here is a nice little jQuery trick that will do it:
var value = $('<textarea/>').html(yourElement.data('options')).val();
You might want to make a function for that, of course.
Sources:
http://aspnet.codeplex.com/
http://refresh-sf.com/blog/2009/05/decode-html-entities-with-jquery/

Resources