Binding radio buttons in ASP.NET MVC page with razor

孤人 提交于 2020-05-30 08:11:11

问题


I have a page with 4 radio buttons (Exam question and 4 options to choose from). With the code below, I can read the option values after user clicks the button.

I have two questions:

  • Why are all radio buttons selected when the page first loads?
  • How to find out which radio button is selected after the post?

Thanks!

StudentQuestions.cshtml

@page "{examId:int?}"
@model VerityLearn.WebUI.Pages.Questions.StudentQuestionsModel
@{
    ViewData["Title"] = "StudentQuestions";
}
    <div>
        <form method="post">
            @Html.LabelFor(model => model.QuestionViewModel.QuestionText);

                <p>Select the correct option.</p>

                int optionIndex = -1;

                @foreach (OptionViewModel opt in Model.QuestionViewModel.Options)
                {
                    optionIndex++;

                    @Html.RadioButtonFor(model => model.QuestionViewModel.Options[optionIndex], Model.QuestionViewModel.Options[optionIndex]);
                    @opt.OptionText<br />
                }

            <button type="submit" asp-route-questionIndex="@(Model.QuestionNdx + 1)" class="btn btn-primary @nextDisabled">Next</button>

        </form>
    </div>

StudentQuestions.cshtml.cs

   public class StudentQuestionsModel : PageModel
    {
        //private readonly VerityContext _context;
        private readonly SignInManager<VerityUser> _signInManager;
        private readonly UserManager<VerityUser> _userManager;
        private readonly IStudentQuesionsUOW _studentQuesionsUOW;
        private readonly VerityLearn.DataAccess.VerityContext _context;

        public StudentQuestionsModel(
            VerityContext context,
            SignInManager<VerityUser> signInManager,
            UserManager<VerityUser> userMrg,
            IStudentQuesionsUOW studentQuesionsUOW
        )
        {
            _context = context;
            _signInManager = signInManager;
            _userManager = userMrg;
            _studentQuesionsUOW = studentQuesionsUOW;
        } // end public StudentQuestionsModel(VerityContext context, SignInManager<VerityUser> signInManager, UserManager<VerityUser> userMrg)

        [BindProperty]
        public QuestionViewModel QuestionViewModel { get; set; }

        [BindProperty]
        public Question Question { get; set; }

        public async Task<IActionResult> OnPostAsync()
        {
            ... Not sure what to do here ...
        }

QuestionViewModel.cs

    public class QuestionViewModel
    {
        public int QuestionId { get; set; }

        public int ExamQuestionOrder { get; set; }

        public string QuestionText { get; set; }

        public bool? IsSingleSelection { get; set; }

        public List<OptionViewModel> Options { get; set; }
    } 

回答1:


The thing you are interested in is the value for the radio button that is selected. In my demo to make things simpler I've assumed it's an id. Suppose the radio buttons have name AnswerSelectedId, then a value labelled with AnswerSelectedId is posted back to the server when the form is submitted. Therefore you need to define a property in your model called AnswerSelectedId so that the model binding can match the two.

Here is a quick demo to show what you are trying to achieve borrowing heavily from Mike Brind's answer.

StudentQuestions.cshtml.cs

public class OptionViewModel
{
    public int Id { get; set; }
    public string OptionText { get; set; }
}

public class QuestionViewModel
{
    public int QuestionId { get; set; }
    public int ExamQuestionOrder { get; set; }
    public string QuestionText { get; set; }
    public bool? IsSingleSelection { get; set; }
    public List<OptionViewModel> Options { get; set; }
}

public class StudentQuestionsModelModel : PageModel
{
    public void OnGet()
    {
        QuestionViewModel = new QuestionViewModel
        {
            QuestionId = 1,
            ExamQuestionOrder = 1,
            QuestionText = "Question1",
            IsSingleSelection = false,
            Options = new List<OptionViewModel>()
            {
                new OptionViewModel
                {
                    Id = 1,
                    OptionText = "Option 1"
                },
                new OptionViewModel
                {
                    Id = 2,
                    OptionText = "Option 2"
                }
            }
        };
    }

    [BindProperty]
    public QuestionViewModel QuestionViewModel { get; set; }

    [BindProperty]
    public int AnswerSelectedId { get; set; }   //this is the key bit

    public async Task<IActionResult> OnPostAsync()
    {
        return Content($"The answer selected was {AnswerSelectedId}");
    }
}

StudentQuestions.cshtml

@page "{examId:int?}"
@model StudentQuestions.Pages.StudentQuestionsModel  

<div>
    <form method="post">
        @Html.LabelFor(model => model.QuestionViewModel.QuestionText);

        <p>Select the correct option.</p>    

        @for (var i = 0; i < Model.QuestionViewModel.Options.Count(); i++)
        {
            <input type="radio" asp-for="AnswerSelectedId" 
                   value="@Model.QuestionViewModel.Options[i].Id" /> 
                  @Model.QuestionViewModel.Options[i].OptionText
                  <br>
        }

        <button type="submit" class="btn btn-primary">Next</button>
    </form>
</div>

Note how the asp-for attribute matches the property AnswerSelectedId in your page model.

When you submit is pressed form data will be sent to the server. If you use the developer tools under form data sent to the server it will look like this (depending on the value selected)

AnswerSelectedId: 1

Then the model binding will bind the value to your property called AnswerSelectedId and you will then be able to access it in your onPostAsync method.




回答2:


I would suggest to use Animated radios & checkboxes (noJS) that is working perfectly fine with its animation effects. You can follow the steps below in order to use it in your Razor pages:

css:

.checkbox label:after, .radio label:after {
    content: '';
    display: table;
    clear: both;
}

.checkbox .cr, .radio .cr {
    position: relative;
    display: inline-block;
    border: 1px solid #a9a9a9;
    border-radius: .25em;
    width: 1.3em;
    height: 1.3em;
    float: left;
    margin-right: .5em;
}

.radio .cr {
    border-radius: 50%;
}

.checkbox .cr .cr-icon, .radio .cr .cr-icon {
    position: absolute;
    font-size: .8em;
    line-height: 0;
    top: 50%;
    left: 20%;
}

.radio .cr .cr-icon {
    margin-left: 0.04em;
}

.checkbox label input[type="checkbox"], .radio label input[type="radio"] {
    display: none;
}

.checkbox label input[type="checkbox"] + .cr > .cr-icon, .radio label input[type="radio"] + .cr > .cr-icon {
    transform: scale(3) rotateZ(-20deg);
    opacity: 0;
    transition: all .3s ease-in;
}

.checkbox label input[type="checkbox"]:checked + .cr > .cr-icon, .radio label input[type="radio"]:checked + .cr > .cr-icon {
    transform: scale(1) rotateZ(0deg);
    opacity: 1;
}

.checkbox label input[type="checkbox"]:disabled + .cr, .radio label input[type="radio"]:disabled + .cr {
    opacity: .5;
}


controller:

public async Task<ActionResult> Edit(int id)
{
    //code omitted for brevity
    return PartialView("_Edit", model);
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Update([Bind(Exclude = null)] GroupViewModel model, 
    params string[] selectedRoles)
{
    //code omitted for brevity
    await this.GroupManager.UpdateGroupAsync(group);
    selectedRoles = selectedRoles ?? new string[] { };
    await this.GroupManager.SetGroupRolesAsync(group.Id, selectedRoles);
}


view:

@model Demo.Models.GroupViewModel

<div class="form-group">
    @Html.Label("Roles", new { @class = "col-md-3 control-label" })
    <div class="col-md-6">

        <div class="checkbox">
            <label>
                <input type="checkbox" id="checkAll" name="" class="" />
                <span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span>
                <text id= "checkText">Tümü?</text> 
            </label>
        </div>

        @foreach (var role in Model.RolesList)
        {
            <div class="checkbox">
                <label>
                    <input type="checkbox" name="selectedRoles" value="@role.Text" checked="@role.Selected" class="" />
                    <span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span>
                    @role.Text
                </label>
            </div>
        }
    </div>
</div>

<script>
    // for selecting All / None
    $("#checkAll").change(function () {
        var checked = $(this).prop("checked");
        $("input:checkbox").prop('checked', checked);
        $('#checkText').text(checked ? 'None?' : 'All?');
    });     
</script>

Hope this helps.




回答3:


If you want to use radio buttons to represent mutually exclusive options, you should group them together by applying the same name attribute value:

<input type="radio" name="question1" value="answer1" /> Answer 1
<input type="radio" name="question1" value="answer2" /> Answer 2
<input type="radio" name="question1" value="answer3" /> Answer 3

The Html helper you are using generates different id and name attribute values for each radio button. I would avoid using Html helpers in Razor Pages in favour of tag helpers:

@for (var i = 0; i <  Model.QuestionViewModel.Options.Count(); i++)
 {
    <input type="radio" asp-for="QuestionViewModel.QuestionId" value="@Model.QuestionViewModel.Options[i]" /> @Model.QuestionViewModel.Options[i].OptionText<br/>
 }

More info: https://www.learnrazorpages.com/razor-pages/forms/radios



来源:https://stackoverflow.com/questions/61741450/binding-radio-buttons-in-asp-net-mvc-page-with-razor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!