Issue With Radio Buttons ASP.Net Core Razor Pages

I am currently having an issue with trying to post information from multiple choice answer options via radio buttons using razor pages and ASP.net Core.
I’ve found some info for MVC but can’t quite fix my issue with it.

I have a Razor page that displays a list of questions and, within each question its possible answer options.
This is my form below:

<form method="post">
    @for (int i = 0; i < Model.Questions.Count(); i++)
    {
        <h4>@Model.Questions.ElementAt(i).QuestionBody</h4>
        <input type="hidden" asp-for="Question.QuestionBody" />

        @foreach (var answer in Model.Answers)
        {
            var groupID = "question" + i;

            <div class="input-group">
                <div class="input-group-prepend">
                    <div class="input-group-text">
                        <input type="radio" name="@groupID" />
                        <label>answer.AnswerBody</label>
                    </div>
                </div>
            </div>
        }
    }
    <button type="submit" class="btn btn-primary">Save</button>
</form>

From info I’ve read I think I need to remove the name attribute but currently it is what is grouping my answers to the correct questions and allowing me to select multiple answers per page.

The Page Model for the ApTest razor page which contains the form is

public class ApTestModel : PageModel
    {
        private readonly IConfiguration config;
        public IApTestData ApTestData { get; set; }

        [BindProperty]
        public IEnumerable<Question> Questions { get; set; }
        [BindProperty]
        public Question Question { get; set; }
        public int QuestionID { get; set; }
        [BindProperty]
        public List<Answer> Answers { get; set; }
        [BindProperty]
        public Answer Answer { get; set; }
        [BindProperty]
        public TestAttempt TestAttempt { get; set; }


        public ApTestModel(IConfiguration config, IApTestData ApTestData)
        {
            this.config = config;
            this.ApTestData = ApTestData;
        }

        public void OnGet()
        {
            Questions = ApTestData.GetQuestionsAndAnswers(QuestionID);

        }

        public void OnPost()
        {
            AppUser appUser = new AppUser
            {
                Email = User.Identity.Name,
            };

            ApTestData.SaveApTestAttempt(Answers, appUser);
        }
    }
}

The SaveApTestAttempt method is here:
public void SaveApTestAttempt(List<Answer> answers, AppUser appUser)
        {
            var tempAppUser = db.Users.SingleOrDefault(user => user.Email == appUser.Email);
            foreach (var answer in answers)
            {
                TestAttempt testAttempt = new TestAttempt
                {
                    SelctedAnswer = answer,
                    Applicant = appUser,
                    ApplicantID = tempAppUser.Id
                };

                db.TestAttempts.Add(testAttempt);
            }
        }

and the entities involved are Question, Answer, and TestAttempt (All seperate classes but combined here for easy viewing):
 public class Question
    {
        public int ID { get; set; }
        public string QuestionBody { get; set; }
        public List<Answer> Answers { get; set; }
        public QuestionTypeID QuestionTypeID { get; set; }
        public QuestionType QuestionType { get; set; }

        public Question()
        {
            Answers = new List<Answer>();
        }
    }

public class Answer
    {
        public int ID { get; set; }
        public string AnswerBody { get; set; }
        public bool IsCorrect { get; set; }
        public Question Question { get; set; }
        public int QuestionID { get; set; }
    }

public class TestAttempt
    {
        [Key]
        public int ID { get; set; }
        public AppUser Applicant { get; set; }
        public string ApplicantID { get; set; }
        public Answer SelctedAnswer { get; set; }
        public int AnswerID { get; set; }


    }

I know I should be binding and using asp-for within my form but I have tried that as well as removing the name attribute and adding a value but I don’t think I am ever adding the correct thing.
I was using something like Model.Questions.ElementAt(i).Answers[j].AnswerID

Still fairly new to the ASP.Net Core world and working on my dissertation project for uni,
Any help would be greatly appreciated!!

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Model binding looks through the sources for the name pattern prefix.property_name. If nothing is found, it looks for just property_name without the prefix.What you define for @groupID cannot be bound to the model due to the name does not match to the property name.

And your code have another error is that you do not define Answers in the handler but you loop it in the razor pages,it is impossible.

public class ApTestModel : PageModel
{
    private readonly IConfiguration config;

    [BindProperty]
    public IEnumerable<Question> Questions { get; set; }
    [BindProperty]
    public Question Question { get; set; }
    public int QuestionID { get; set; }
    [BindProperty]
    public List<Answer> Answers { get; set; }
    [BindProperty]
    public Answer Answer { get; set; }
    [BindProperty]
    public TestAttempt TestAttempt { get; set; }


    public PrivacyModel(IConfiguration config)
    {
        this.config = config;
    }

    public void OnGet()
    {
        Questions = new List<Question>()
        {
            new Question(){
                ID=1,
                QuestionBody="question1"                    
            },
            new Question(){
                ID=2,
                QuestionBody="question2"
            },
            new Question(){
                ID=3,
                QuestionBody="question3"
            }
        };
        Answers = new List<Answer>(){
                    new Answer() {ID=1, AnswerBody="an1", QuestionID=1} ,
                    new Answer() {ID=2, AnswerBody="an2", QuestionID=1} ,
                    new Answer() {ID=3, AnswerBody="an3", QuestionID=1} 
                };
    }

    public void OnPost()
    {
        AppUser appUser = new AppUser
        {
            Email = "aaaa",
        };

        SaveApTestAttempt(Answers, appUser);
    }
    public void SaveApTestAttempt(List<Answer> answers, AppUser appUser)
    {
        //...
    }
}

Change your razor pages like below(Not sure which value in Answer class you want to bind to the radio button.You could change the name by yourself):
<form method="post">
    @for (int i = 0; i < Model.Questions.Count(); i++)
    {
        <h4>@Model.Questions.ElementAt(i).QuestionBody</h4>
        <input type="hidden" name="[@i].QuestionBody" asp-for="@Model.Questions.ElementAt(i).QuestionBody" />

        @foreach (var answer in Model.Answers)
        {
            var groupID = "[" + i + "].AnswerBody";
            <input type="hidden" asp-for="@answer.ID" />
            <div class="input-group">
                <div class="input-group-prepend">
                    <div class="input-group-text">
                     <input type="radio" name="@groupID" value="@answer.AnswerBody" />
                        <label>@answer.AnswerBody</label>
                    </div>
                </div>
            </div>
        }
    }
    <button type="submit" class="btn btn-primary">Save</button>
</form>

Result:

Issue With Radio Buttons ASP.Net Core Razor Pages


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x