views:

82

answers:

1

This one has me stumped, I have a strongly typed view that has this loop to generate radiobuttons:

<% foreach (QuestionAnswer qa in Model.QuestionAnswers)
   { %>
    <%= Html.RadioButtonFor(model => model.QuestionAnswers[(int)qa.QuestionID - 1].AnswerValue, "Checked" ) %>
    <%= Html.Encode(qa.OptionValue) %>
<% } %>

It renders fine, but since the names are not the same, you can select more than 1 radiobutton. How can I group them so only 1 radiobutton can be selected?

Any help would be appreciated!

+1  A: 

The first parameter of Html.RadioButtonFor() should be the property name you're using, and the second parameter should be the value of that specific radio button. Then they'll have the same name attribute value and the helper will select the given radio button when/if it matches the property value.

Example:

<div class="editor-field">
    <%= Html.RadioButtonFor(m => m.Gender, "M" ) %> Male
    <%= Html.RadioButtonFor(m => m.Gender, "F" ) %> Female
</div>

Here's a more specific example:

I made a quick MVC project named "DeleteMeQuestion" (DeleteMe prefix so I know that I can remove it later after I forget about it).

I made the following model:

namespace DeleteMeQuestion.Models
{
    public class QuizModel
    {
        public int ParentQuestionId { get; set; }
        public int QuestionId { get; set; }
        public string QuestionDisplayText { get; set; }
        public List<Response> Responses { get; set; }

        [Range(1,999, ErrorMessage = "Please choose a response.")]
        public int SelectedResponse { get; set; }
    }

    public class Response
    {
        public int ResponseId { get; set; }
        public int ChildQuestionId { get; set; }
        public string ResponseDisplayText { get; set; }
    }
}

There's a simple range validator in the model, just for fun. Next up, I made the following controller:

namespace DeleteMeQuestion.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        public ActionResult Index(int? id)
        {
            // TODO: get question to show based on method parameter 
            var model = GetModel(id);
            return View(model);
        }

        [HttpPost]
        public ActionResult Index(int? id, QuizModel model)
        {
            if (!ModelState.IsValid)
            {
                var freshModel = GetModel(id);
                return View(freshModel);
            }

            // TODO: save selected answer in database
            // TODO: get next question based on selected answer (hard coded to 999 for now)

            var nextQuestionId = 999;
            return RedirectToAction("Index", "Home", new {id = nextQuestionId});
        }

        private QuizModel GetModel(int? questionId)
        {
            // just a stub, in lieu of a database

            var model = new QuizModel
            {
                QuestionDisplayText = questionId.HasValue ? "And so on..." : "What is your favorite color?",
                QuestionId = 1,
                Responses = new List<Response>
                                                {
                                                    new Response
                                                        {
                                                            ChildQuestionId = 2,
                                                            ResponseId = 1,
                                                            ResponseDisplayText = "Red"
                                                        },
                                                    new Response
                                                        {
                                                            ChildQuestionId = 3,
                                                            ResponseId = 2,
                                                            ResponseDisplayText = "Blue"
                                                        },
                                                    new Response
                                                        {
                                                            ChildQuestionId = 4,
                                                            ResponseId = 3,
                                                            ResponseDisplayText = "Green"
                                                        },
                                                }
            };

            return model;
        }
    }
}

Finally, I made the following view that makes use of the model:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<DeleteMeQuestion.Models.QuizModel>" %>

<asp:Content ContentPlaceHolderID="TitleContent" runat="server">
    Home Page
</asp:Content>

<asp:Content ContentPlaceHolderID="MainContent" runat="server">

    <% using (Html.BeginForm()) { %>

        <div>

            <h1><%: Model.QuestionDisplayText %></h1>

            <div>
            <ul>
            <% foreach (var item in Model.Responses) { %>
                <li>
                    <%= Html.RadioButtonFor(m => m.SelectedResponse, item.ResponseId, new {id="Response" + item.ResponseId}) %>
                    <label for="Response<%: item.ResponseId %>"><%: item.ResponseDisplayText %></label>
                </li>
            <% } %>
            </ul>

            <%= Html.ValidationMessageFor(m => m.SelectedResponse) %>

        </div>

        <input type="submit" value="Submit" />

    <% } %>

</asp:Content>

As I understand your context, you have questions with a list of available answers. Each answer will dictate the next question. Hopefully that makes sense from my model and TODO comments.

This gives you the radio buttons with the same name attribute, but different ID attributes.

AndrewDotHay
Thanks Andrew, but I think the name field is causing the problem since it is part of a loop. When I look at the source, it shows AnswerValue[1], AnswerValue[2], etc...To be able to return the Strongly Typed result this naming is necessary (I would like to store each radio button in it's own field). Just wondered if there was any way to make only a single selection functionality.
Mark Kadlec
Can you share a slim version of your model's class definition and intent? Is your code loop tasked with creating radio buttons for a single question and all of its answers? Which property stores the selected value? Stuff like that would help describe what you want to do.
AndrewDotHay
I'm still in the development stages, so open to solutions. Basically we want to present questions to the user with multiple choice results drawn from a DB. Each result is a question as well, with the parentQuestionID being the main question.Slimmed Model would be public class QuestionAnswer { public int QuesitonID {}, public string QuestionText {}, public string OptionValue {}, public string AnswerValue {}.I would pass a list of this model in. I've added my loop code to the original question.
Mark Kadlec
Thanks Andrew, my problem was that the selected value was not stored in the parent question, but each value had it's own questionID. I had to use the name property, but you have given me an idea to model with a separate table to hold option values.Thanks a lot for your help and I think the new model will work better anyways, especially if it means I can do a strongly typed result.
Mark Kadlec