1

I have an editor template Duration that holds four simple radio buttons.
I am using this template for a property on my class Test. I cannot get this property to bind to the radio button list and select the correct radio button on load. Selecting a value and submitting will return the correct value. I have tried changing the values of the radio buttons to a variety of different values, but to no avail.
What value should I pass to RadioButtonFor to get this to work? Ideally this editor template takes in nullable float and still works.

Duration.cshtml

@model float
<h3>Model Value: @Model</h3>
@Html.RadioButtonFor(model => model, 0.25F, new { id = "btnQuarterDay" }) @(.25F)
@Html.RadioButtonFor(model => model, 0.5F, new { id = "btnHalfDay" }) @(.5F)
@Html.RadioButtonFor(model => model, 0.75F, new { id = "btnThreeQuarterDay" }) @(.75F)
@Html.RadioButtonFor(model => model, 1.0F, new { id = "btnOneDay" }) @(1.0F)

Test.cs

public class Test
{
    [UIHint("Duration")]
    [Display(Name = "Days")]
    public float Duration { get; set; }   
}

HomeController

public class HomeController : Controller
{
    public ActionResult Index(float? duration = null)
    {
        var model = new Test
        {
            Duration = duration.GetValueOrDefault(1F)
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(Test model)
    {
        ViewBag.Success = true;
        ViewBag.ValueSelected = model.Duration;
        return View(model);
    }
}

Index.cshtml

@model RadioButtonForTest.Models.Test

@using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
    <div class="row">
        <div class="col-md-4">
            @Html.EditorFor(model => model.Duration)
            @Html.ValidationMessageFor(model => model.Duration)
        </div>
    </div>

    <button type="submit" class="btn btn-primary">Submit</button>
    if (ViewBag.Success ?? false)
    {
        <span>Value Selected:</span> @ViewBag.ValueSelected
    }
}

UPDATE: Plot Thickener
I wired up the Index action to take in duration, so that I can pass it via the query string. If a value is not passed via the query string. It will select the radio button below:

@Html.RadioButton("", Model, Model.Equals(1.0F), new { id = "radbtnOneDay4" })

If I navigate to the query string /Home/Index?duration=.5 NOTHING is selected, but when debugging Duration.cshtml Model.Equals(.50F) reports TRUE. So I would expect this radio button to be selected:

@Html.RadioButton("", Model, Model.Equals(.50F), new { id = "radbtnHalfDay4" })

Is this not crazy? Why is it not checking this radio button??? Is this a bug? Is there a custom model binders I could add to handle floats?

UPDATE 2
The query string parameter duration matches the model name and the query string is overriding the model value.
When I changed the parameter to be dur it worked fine. Using the following URL it would use the value from the ViewModel. /Home/Index?dur=.5
I know there is a solid reason behind this...but this has been exasperating.

Airn5475
  • 2,452
  • 29
  • 51
  • Not sure why it will not work with your EditorTemplate, but it will work if your include `@Html.RadioButtonFor(m => m.Duration, 0.25F)` etc directly in the main view –  Sep 30 '16 at 05:43
  • Plot thickening: there is sometimes a difference in what the html helpers use for model values and what the debugger shows. See http://stackoverflow.com/questions/1775170/asp-net-mvc-modelstate-clear for more info – Pitchmatt Sep 30 '16 at 14:07

2 Answers2

0

The RadioButtonFor helper does not work in templates (edit: ... in cases like yours when using it to bind to simple member values as model => model expression will become an empty name). You need to change your template code to

@Html.RadioButton("", 0.25F, Model == 0.25F, new { id = "btnQuarterDay" }) @(.25F)
@Html.RadioButton("", 0.5F, Model == 0.5F, new { id = "btnHalfDay" }) @(.5F)
@Html.RadioButton("", 0.75F, Model == 0.75F, new { id = "btnThreeQuarterDay" }) @(.75F)
@Html.RadioButton("", 1.0F, Model == 1.0F, new { id = "btnOneDay" }) @(1.0F)

Edit#2: another alternative would be to use a more complex model:

public class DurationContainer {
    public float Duration { get; set; }
}

public class Test2 {

    [UIHint("Duration2")]
    public DurationContainer Container { get; set; }
}

Index.cshtml:

@Html.EditorFor(model => model.Container)

And then as Duration2.cshtml template:

@Html.RadioButtonFor(model => model.Duration, 0.25F, new { id = "btnQuarterDay" }) @(.25F)
@Html.RadioButtonFor(model => model.Duration, 0.5F, new { id = "btnHalfDay" }) @(.5F)
@Html.RadioButtonFor(model => model.Duration, 0.75F, new { id = "btnThreeQuarterDay" }) @(.75F)
@Html.RadioButtonFor(model => model.Duration, 1.0F, new { id = "btnOneDay" }) @(1.0F)
Pitchmatt
  • 1,364
  • 1
  • 9
  • 10
  • Actually `RadioButtonFor` works perfectly well in templates. The issue caused by the `model => model` expression - which is not valid. – Alex Art. Sep 30 '16 at 06:09
  • @AlexArt. I respectfully and simply must disagree after burning up hours on this one. – Airn5475 Sep 30 '16 at 13:14
  • @Pitchmatt Thank you for your response. See my update above. I'm using `Model.Equals` and am having no luck EVEN THOUGH the debugger says it should be selected. I can't even get the the right value to post. – Airn5475 Sep 30 '16 at 13:22
  • @Airn5475 I just tested the first version again and it works for me, even for posts. Note the fixed typo in the `@Html.RadioButton(...`part so if you copied the first template post some hours ago you might need to copy it again – Pitchmatt Sep 30 '16 at 14:49
  • @Pitchmatt yes, I found the same typo when debugging and posted the change in my first Update above. I thought about your alternative approach as well, but seems to add an extra layer of complication. Thanks for your help on this one! – Airn5475 Sep 30 '16 at 15:33
0

Your editor template is not working because the first argument of is supposed to be a member expression to models property and not a model itself so model => model is what's wrong. You can easily fix it by using Html.RadioButton instead of `Html.RadioButtonFor. Notice that instead of specifying a property name we simply passing an empty string. The reason for that is that EditorTemplates generate are generating correct property names by appending prefixes form parrent model. So your template should look like that:

@model float
<h3>Model Value: @Model</h3>
@Html.RadioButton("", 0.25F, new { id = "btnQuarterDay" }) @(.25F)
@Html.RadioButton("", 0.5F, new { id = "btnHalfDay" }) @(.5F)
@Html.RadioButton("", 0.75F, new { id = "btnThreeQuarterDay" }) @(.75F)
@Html.RadioButton("", 1.0F, new { id = "btnOneDay" }) @(1.0F)
Alex Art.
  • 8,711
  • 3
  • 29
  • 47
  • Thank you for your response. Unfortunately this one isn't working for me. The radio button that corresponds to the the Model is not being selected. If I select one and submit, it does post the correct value back. – Airn5475 Sep 30 '16 at 12:57