Required Field Validation Doesn't Work Across Tabs

I'm able to submit a form even though some fields haven't met the required field validation. This happens if the field is on a tab (RadzenTabs) that is not visible. Any thoughts on how to correct this?

@page "/add-modalityzzz"
@layout MainLayout
@inherits ProgramAdminTool.Pages.AddModalityzzzComponent

@using Radzen
@using Radzen.Blazor
@using ProgramAdminTool.Models.ProgramDb
@using Microsoft.AspNetCore.Identity;
@using ProgramAdminTool.Models
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]


<RadzenContent Container="main">
  <ChildContent>
    <RadzenHeading Size="H1" Text="Add Modalityzzz">
    </RadzenHeading>
    <div class="row">
      <div class="col-md-12">
        <RadzenTemplateForm Data="@modality" TItem="ProgramAdminTool.Models.ProgramDb.Modality" Visible="@(modality != null)" Submit="@Form0Submit">
          <ChildContent>
            <div style="margin-bottom: 1rem" class="row">
              <div class="col-md-3">
                <RadzenLabel Component="Active" style="width: 100%" Text="Active">
                </RadzenLabel>
              </div>
              <div class="col-md-9">
                <RadzenCheckBox @bind-Value="@(modality.Active)" Name="Active">
                </RadzenCheckBox>
              </div>
            </div>
            <div style="margin-bottom: 1rem" class="row">
              <div class="col-md-3">
                <RadzenLabel Component="InsertDate" style="width: 100%" Text="Insert Date">
                </RadzenLabel>
              </div>
              <div class="col-md-9">
                <RadzenDatePicker style="display: block; width: 100%" @bind-Value="@(modality.InsertDate)" Name="InsertDate">
                </RadzenDatePicker>
                <RadzenRequiredValidator Component="InsertDate" style="position: absolute" Text="InsertDate is required">
                </RadzenRequiredValidator>
              </div>
            </div>
            <div style="margin-bottom: 1rem" class="row">
              <div class="col-md-3">
                <RadzenLabel Component="UpdateBy" style="width: 100%" Text="Update By">
                </RadzenLabel>
              </div>
              <div class="col-md-9">
                <RadzenTextBox MaxLength="100" style="display: block; width: 100%" @bind-Value="@(modality.UpdateBy)" Name="UpdateBy">
                </RadzenTextBox>
                <RadzenRequiredValidator Component="UpdateBy" style="position: absolute" Text="UpdateBy is required">
                </RadzenRequiredValidator>
              </div>
            </div>
            <div style="margin-bottom: 1rem" class="row">
              <div class="col-md-3">
                <RadzenLabel Component="UpdateDate" style="width: 100%" Text="Update Date">
                </RadzenLabel>
              </div>
              <div class="col-md-9">
                <RadzenDatePicker style="display: block; width: 100%" @bind-Value="@(modality.UpdateDate)" Name="UpdateDate">
                </RadzenDatePicker>
                <RadzenRequiredValidator Component="UpdateDate" style="position: absolute" Text="UpdateDate is required">
                </RadzenRequiredValidator>
              </div>
            </div>
            <RadzenTabs>
              <Tabs>
                <RadzenTabsItem Selected="false" Text="Tab 1">
                  <ChildContent>
                    <div style="margin-bottom: 1rem" class="row">
                      <div class="col-md-3">
                        <RadzenLabel Component="Name" style="width: 100%" Text="Name">
                        </RadzenLabel>
                      </div>
                      <div class="col-md-9">
                        <RadzenTextBox MaxLength="100" style="display: block; width: 100%" @bind-Value="@(modality.Name)" Name="Name">
                        </RadzenTextBox>
                        <RadzenRequiredValidator Component="Name" style="position: absolute" Text="Name is required">
                        </RadzenRequiredValidator>
                      </div>
                    </div>
                  </ChildContent>
                </RadzenTabsItem>
                <RadzenTabsItem Selected="true" Text="Tab 2">
                  <ChildContent>
                    <div style="margin-bottom: 1rem" class="row">
                      <div class="col-md-3">
                        <RadzenLabel Component="InsertBy" style="width: 100%" Text="Insert By">
                        </RadzenLabel>
                      </div>
                      <div class="col-md-9">
                        <RadzenTextBox MaxLength="100" style="display: block; width: 100%" @bind-Value="@(modality.InsertBy)" Name="InsertBy">
                        </RadzenTextBox>
                        <RadzenRequiredValidator Component="InsertBy" style="position: absolute" Text="InsertBy is required">
                        </RadzenRequiredValidator>
                      </div>
                    </div>
                  </ChildContent>
                </RadzenTabsItem>
              </Tabs>
            </RadzenTabs>
            <div class="row">
              <div class="col offset-sm-3">
                <RadzenButton ButtonStyle="ButtonStyle.Primary" ButtonType="ButtonType.Submit" Icon="save" Text="Save">
                </RadzenButton>
                <RadzenButton ButtonStyle="ButtonStyle.Light" style="margin-left: 1rem" Text="Cancel" Click="@Button2Click">
                </RadzenButton>
              </div>
            </div>
          </ChildContent>
        </RadzenTemplateForm>
      </div>
    </div>
  </ChildContent>
</RadzenContent>

By default RadzenTabs renders only the current tab. This is why any invisible validators don't register with the RadzenTemplateForm. You can try changing the RenderMode property to Client:

<RadzenTabs RenderMode="TabRenderMode.Client">

This will make all tabs render instead of just the current one. The validator in hidden tabs should register with the form and prevent form submission. It will not be visible though.

Thank you, this worked.

@korchev, do you have any suggestions how I can alert the user if they try to submit the form but a field is invalid on a tab that isn't visible? Is there a way to display a notification?

You can check if the form is valid via its IsValid property (you will need to get a @ref to it first). Then display some info to your user e.g. 'There are required fields in the other tabs.'

Thanks @korchev I added a click event to the submit button. But I'm not sure how to get a reference to the form. Can you provide a example please? Below is what I have so far.

protected async System.Threading.Tasks.Task Button1Click(MouseEventArgs args)
{
          //get reference to form? 
          //check if form is valid
          //if not display notification. 
          NotificationService.Notify(new NotificationMessage() { Severity = NotificationSeverity.Warning, Summary = $"Error", Detail = $"Validation Error, Please check all tabs for invalid fields." });
}

You can check here: Upload component "Open" click event - #2 by korchev

Just change the type of the property to RadzenTemplateForm<ProgramAdminTool.Models.ProgramDb.Modality>

Thanks @korchev, I was able to get a reference to the form but the isValid property is true even though there are required field validations that aren't met.

I'm probably checking isValid too soon. I'm checking on button click and the validation hasn't run yet. When should I check to see if the form is valid?

Indeed this is too soon. Validation runs during form submission. You can handle the InvalidSubmit event of the TemplateForm - it would be the easiest solution.

perfect solution. Thank you.