Wizard ValidationSummary use with Partial View content

1 Answer 327 Views
Wizard
Richard
Top achievements
Rank 3
Iron
Iron
Iron
Richard asked on 01 Feb 2023, 02:24 PM

Good afternoon,

I am using the wizard component with a partial view on step 1, and a form on step 2.

 @(Html.Kendo().Wizard()
        .Name("uploadWizard")
        .Events(events => {
            events.Select("onFormSelect");
            events.FormValidateFailed("onFormValidateFailed");
        })
        .ValidateForms(v => v.ValidateOnPrevious(false))
        .LoadOnDemand(true)
        .ReloadOnSelect(false)
        .Steps(s => {
            s.Add()
                .Title("Choose Route")
                .ContentId("chooseRoute")
                .Buttons(b =>
                {
                    b.Next();
                });
            s.Add<TransactionViewModel>()
                .Title("File Details")
                .Form(form =>
                {
                    form.FormData(Model);
                    form.Items(items =>
                    {
                        items.Add()
                            .Field(f => f.FileVersion)
                            .Label(label => label.Text("Version of file (if applicable) e.g. 1.00:")
                            .Optional(true))
                            .InputHtmlAttributes(new { @maxlength = "50" });
                        items.Add()
                            .Field(f => f.FileDescription)
                            .Label(label => label.Text("Description of file use/content:"))
                            .Editor(e => e.TextArea()
                            .MaxLength(256)
                            .Rows(2)
                        );
                        items.Add()
                            .Field(f => f.BusinessReason)
                            .Label(label => label.Text("Business reason for the transfer:"))
                            .Editor(e => e.TextArea()
                            .MaxLength(256)
                            .Rows(2)
                        );
                        items.Add().Field(f => f.SourceUri).Label(label => label.Text("Source URI (if from an identifiable source):").Optional(true));
                    });
                })
                .Buttons(b =>
                {
                    b.Previous();
                    b.Next();
                });
            s.Add().Title("Upload File").Content("Upload file");
        })
    )

The partial view content contains a Kendo dropdownlist and a Kendo grid. I need the user to have selected a value from the dropdownlist and the grid before the step 1 wizard button allows the navigation to step 2.

I have added required text inputs to the partial view to capture the required value of the dropdownlist and id of the selected row in the grid. I'm going to hide the inputs but I want the "this field is required" error messages to appear in a validation summary, as they do on the step 2 form.

I've tried adding @Html.ValidationSummary() to the partial view but the error messages still appear next to the text inputs (which are due to be hidden).  The partial view isn't based on a model.

The wizard's select event checks if the two inputs are valid and prevents the user from moving on:

               // Get the current step's container element
                var container = e.sender.currentStep.element;
                // Instantiate a validator for the container element
                $(container).kendoValidator();
                // Get the validator's reference
                var validator = $(container).kendoValidator().data("kendoValidator");
                // Validate a given input elements
                if (!validator.validateInput($("#SourceEnvironmentId")) || !validator.validateInput($("#RouteId"))) {
                    // Prevent the wizard's navigation
                    e.preventDefault();
                }

How do I get the validation error messages for the hidden inputs to appear in the validation summary on step 1?

Kind regards,

Richard

1 Answer, 1 is accepted

Sort by
0
Accepted
Alexander
Telerik team
answered on 06 Feb 2023, 11:48 AM

Hi Richard,

Thank you for reaching out and for taking the time to share the relevant Wizard configuration that is currently utilized on your premises.

Generally, the internal implementation of the Wizard component relies on having the specified fields on each of the steps bound to a given Model. Furthermore, the instantiated validator instances are primarily revolved around the integration of forms and the fields that are associated with them. From there, the Validation Summary's messages are based on the state of those fields.

With that in mind, based on the current information so far, I am not sure I am able to fully understand the given scenario that is being held at hand. In this regard, could you please consider sharing the implemented partial view logic containing the hidden fields as well as the DropDown and Grid components as well?

I may be missing something pivotal, so any additional information would be greatly appreciated.

Looking forward to hearing back from you.

Kind Regards,
Alexander
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Richard
Top achievements
Rank 3
Iron
Iron
Iron
commented on 06 Feb 2023, 12:48 PM

Afternoon Alexander,

Many thanks for your reply.

I have attached the Partial View.  It is included as content using the kendo-template.

        .Steps(s => {
            s.Add()
                .Title("Choose Route")
                .ContentId("chooseRoute")
                .Buttons(b =>
                {
                    b.Next();
                });
<script id="chooseRoute" type="text/kendo-template">
    @await Html.PartialAsync("_UploadRoute")
</script>

As I mentioned, what I would like to achieve on Step 1 is that the user must choose a value from the dropdownlist, and click on a row from the grid - the grid's data is dependent on the dropdownlist.

When the user clicks the Next button I would like the validation error messages for the required dropdownlist selected value and selected grid id to appear in a summary at the top of the form, as they do for Step 2 (a form with textboxes).

Rather than validate the dropdownlist and grid, I thought it would be easier to have two textboxes (which I will hide) to store the selected values, and it's these values that are checked when the Next button is clicked.  Currently the validation messages appear next to the textboxes rather than in a validation summary.

Kind regards,

Richard

Richard
Top achievements
Rank 3
Iron
Iron
Iron
commented on 06 Feb 2023, 05:14 PM

Good afternoon Alexander,

I have tried using a similar method to what's used in the following link:

https://docs.telerik.com/kendo-ui/knowledge-base/validate-radio-buttons

I have added a div (route-summary) to the partial view used in Step 1.

On the Select event for the wizard, the following is called:

        function onFormSelect(e) {
            // Get the current step's index
            var stepIndex = e.step.options.index;
            // Get the current step's container element
            var container = e.sender.currentStep.element;

            // Validate first step
            if (stepIndex == 1) {
                // Instantiate a validator for the container element
                $(container).kendoValidator({
                    validationSummary: {
                        container: "#route-summary"
                    }
                });
                // Get the validator's reference
                var validator = $(container).kendoValidator().data("kendoValidator");
                // Validate given input elements
                if (!validator.validate()) {
                    // Prevent the wizard's navigation
                    e.preventDefault();
                }
            }
            else if (stepIndex == 3) {
                var methodValidator = $(container).kendoValidator({
                    validationSummary: { container: "#method-summary" },
                    rules: {
                        radio: function (input) {
                            if (input.filter("[type=radio]") && input.attr("required")) {
                                return $(container).find("[type=radio][name=" + input.attr("name") + "]").is(":checked");
                            }
                            return true;
                        }
                    },
                    messages: {
                        radio: "Choose method is a required field"
                    }
                }).getKendoValidator();

                if (!methodValidator.validate()) {
                    $($('[data-field="uploadType"]').parent()).hide();
                    $($('[data-field="uploadType"]')[0]).parent().show()
                    // Prevent the wizard's navigation
                    e.preventDefault();
                }
            }
        }

Step 3 is a radio button group and uses this template:

<script id="chooseMethod" type="text/kendo-template">
    <div id="method-summary">
    </div>
    <span class="k-invalid-msg" data-for="uploadType"></span><br/>
    @(Html.Kendo().RadioGroup()
            .Name("uploadType")
            .Items(i =>
            {
                i.Add().Label("I want to upload a file").Value("1");
                i.Add().Label("I want to choose from files in the Source Folder").Value("2");
            })
            .HtmlAttributes(new { required = "required" })
            .Events(e => e.Select("onUploadTypeSelect"))
            .Deferred(true)
    )
</script>

The validation message for Step 3 appears in the Validation summary (method-summary), albeit with the incorrect message ("uploadType is required" instead of "Choose method is a required field").

The validation message for Step 1 in the Validation summary (route-summary) does not appear.

Kind regards,

Richard

Alexander
Telerik team
commented on 09 Feb 2023, 12:24 PM

Hi Richard,

Thank you for the additionally provided resources on your end and the additional clarifications provided in the subsequent comments, it really helped me get a better overall understanding of what the currently held scenario is at your end.

Indeed, having separate validation associated with hidden TextBox is indeed a viable scenario on your end. After thoroughly examining the provided configurations, I noticed the following factors that could potentially prove to be the current culprits for the unorthodox behaviors. Please allow me to go through each of them in further detail:

In regards to the required message behavior on your end:

The issue would most notably stem from the fact that the Kendo Validator provides its own set of messages for required message validation. However, the Validation also exposes the ability to override the built-in validations directly within the boundaries of the "messages" configuration. Thus, in your scenario, in particular, a possible suggestion would be to alter the validator initialization as follows:

var methodValidator = $(container).kendoValidator({
                validationSummary: { container: "#method-summary" },
                rules: {
                    required: function (input) {
                        if (input.filter("[type=radio]") && input.attr("required")) {
                            return $(container).find("[type=radio][name=" + input.attr("name") + "]").is(":checked");
                        }
                        return true;
                    }
                },
                messages: {
                   required: function(input) { // Override the default required message.
                     return "MyMessage";
               }

            }
  }).getKendoValidator();

This would produce the following result:

In regards to the behavioral anomalies within the first step:

Upon further investigation, the issue potentially arises due to the fact that the utilized TextBox editors are initialized outside the boundaries of the Wizard Step's content. From there, the validation would be able to execute accordingly if it is reliant on those two controls.

This is due to the fact that not all the controls are deferred, causing the components to be rendered immediately after the HTML markup when they are nested in the Wizard and loaded through a template. This has been further discussed within the following topic:

As mentioned, there the .Deferred() API configuration should be declared for each of the controls allocated within the specified Partial View.

With that in mind, additionally, I noticed that the validator is instantiated multiple times within the specified logic for the first step which would cause the options to be overridden and thus, obscure the Validation Summary:

// Validate first step
if (stepIndex == 1) {
    // Instantiation #1
    $(container).kendoValidator({
        validationSummary: {
            container: "#route-summary"
        }
    });
    ...
    var validator = $(container).kendoValidator().data("kendoValidator"); // Instantiation #2
    ...
}

Hence, I recommend obtaining the validator's reference as follows:

 var validator = $(container).data("kendoValidator");

The aforementioned configuration would then produce the following result for the first step upon validation:

That being said, for your convenience, I am also attaching a runnable sample that further showcases the mentioned above recommendations with an identical configuration as yours. Notice, that I have altered the _UploadRoute partial view by integrating TextBoxFor HTML Helper that the Telerik UI for ASP.NET Core provides

Feel free to modify the sample and to further implement the desired logic for a population of the TextBoxes as per your requirements.

I hope this helps during your endeavors.

 

Richard
Top achievements
Rank 3
Iron
Iron
Iron
commented on 09 Feb 2023, 02:20 PM

Many thanks Alexander for your solutions and explanations - they were really helpful!

I have positioned and hidden the textboxes above the dropdown list and grid on the partial view, and made them deferred too:

    @Html.Kendo().TextBox().Name("SourceEnvironmentId").HtmlAttributes(new { style = "display: none;", required = "required", validationMessage = "Source Environment is required." }).Deferred()
    @(Html.Kendo().DropDownList()
...
...
    @Html.Kendo().TextBox().Name("RouteId").HtmlAttributes(new { style = "display: none;", required = "required", validationMessage = "Route selection is required." }).Deferred()
    @(Html.Kendo().Grid<RouteViewModel>()

The messages appear correctly:

Thanks once again for all your help.

Kind regards,

Richard 

Tags
Wizard
Asked by
Richard
Top achievements
Rank 3
Iron
Iron
Iron
Answers by
Alexander
Telerik team
Share this question
or