Darf Zon
Darf Zon

Reputation: 6378

How to validate the form in this scenario

@model Contoso.MvcApplication.ViewModels.QuizCompletedViewModel

<h2>Quiz 1</h2>

<form method="post">
@for (int i = 0; i < Model.Questions.Count; i++) {
    @Html.EditorFor(model => model.Questions[i], "Questions/_MultipleChoiceAnswerView")
}

<div>
    <p style="float: left;">Question @ViewData["CurrentNumber"] of @ViewData["TotalQuestions"]</p>
    <input type="submit" value="Continue" style="float: right;" />
</div>
</form>

As you can see, I'm showing all the questions through the loop. But I really want to show question by question in the page. This is the a related post to implement it.

Hide current element and show the next one

If I don't include that JQuery feature, it looks like this

enter image description here

And the problem is, with the last JQUERY feature, I'm going to show only one question at a time, so I need to validate only that question, and that's the part I really have no idea.

I mean, suppose that I've already that JQUERY function, so when the user press CONTINUE, it has to validate if the current question is valid, but only this, not all.

What can I do?

UPDATE: The code where I create the radio buttons:

@using Contoso.MvcApplication.Extensions
@model Contoso.MvcApplication.ViewModels.MultipleChoiceQuestionViewModel

<div class="question-container">
    <h5>@Model.Question.QuestionText</h5>
</div>

<div class="answer-container">
@Html.RadioButtonForSelectList(m => Model.Question.SelectedAnswer, Model.AnswerRadioList)
@Html.ValidationMessageFor(m => m.Question.SelectedAnswer)
</div>

And I'm using HtmlExtensions:

public static class HtmlExtensions
{
    public static MvcHtmlString RadioButtonForSelectList<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression,
        IEnumerable<SelectListItem> listOfValues,
        IDictionary<string, object> htmlAttributes)
    {
        var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        var sb = new StringBuilder();

        if (htmlAttributes == null)
        {
            htmlAttributes = new RouteValueDictionary();
        }
        if (!htmlAttributes.ContainsKey("id"))
        {
            htmlAttributes["id"] = null;
        }
        foreach (SelectListItem item in listOfValues)
        {
            var id = string.Format(
                "{0}_{1}",
                htmlHelper.ClientIdFor(expression),
                item.Value
            );
            htmlAttributes["id"] = id;
            var radio = htmlHelper.RadioButtonFor(expression, item.Value, htmlAttributes).ToHtmlString();
            var labelId = htmlHelper.ClientIdFor(expression);
            sb.AppendFormat(
                "<div class='rad'>{0}<label for=\"{1}\">{2}</label></div>",
                radio,
                id,
                HttpUtility.HtmlEncode(item.Text)
            );
        }

        return MvcHtmlString.Create(sb.ToString());
    }
}

Upvotes: 0

Views: 226

Answers (1)

heads5150
heads5150

Reputation: 7463

Look at using something like the following. It uses the visible div as the current step and looks for invalid elements contained within.

This is a rough set of code and has not been tested but hopefully it might give you an idea on how to proce

// attach continue button handler       
        $("#continue).click(function ()
        {

            var $step = $(":visible"); // get current step

            var validator = $("form").validate(); // obtain validator
            var anyError = false;

            //find any elements within the current step that are invalid.
            $step.find("input").each(function ()
            {
                if (!validator.element(this)) { // validate every input element inside this step
                    anyError = true;
                }

            });

            if (anyError)
                return false; // exit if any error found

                //in this case use class confirm (or use hidden field value for step number)
            if ($step.next().hasClass("confirm")) { // is it confirmation?
                // show confirmation asynchronously
                $.post("/wizard/confirm", $("form").serialize(), function (r)
                {
                    // inject response in confirmation step
                    $(".confirm").html(r);
                });
            }
               //workout if this is the last step.
               //if not go to next question
               // if it is submit the form
            if ($step.next().hasClass("complete")) { // is there any next step?
                $step.hide().next().show();  // show it and hide current step
                $("#back-step").show();   // recall to show backStep button
            }

            else { // this is last step, submit form
                $("form").submit();
            }


        });

Upvotes: 1

Related Questions