Triggering RadzenRequiredValidator in a childcomponent upon clicking Save in an other child component

Hi,

We are using a RadzenTemplateForm in a RadzenSteps. This templateform has a TitleTooltip child component which holds a textarea "Title" with a RadzenRequiredValidator and a textarea "ToolTip". The templateform also has a SaveCancel child component which holds the Save and cancel functionality.
How can I have the RadzenRequiredValidator show up when clicking the Save button if the title field is empty?

Hi @TinoS,

You can check this thread: Radzen validators in nested components - #2 by korchev

Hi @korchev,
Thx for your quick response.

I looked at this example before. However my issue is more complex I think.

Radzensteps.razor:

<RadzenSteps @bind-SelectedIndex="@selectedIndex" ShowStepsButtons="false">
  <Steps>
    <RadzenStepsItem Text="@Localizer["Questions"]">

      <RadzenStack Orientation="Orientation.Vertical" AlignItems="AlignItems.Center">
        <RadzenButton Text="@Localizer["YesNo"]" Style="width: 200px" Click="@(_ => OnQuestionTypeSelected(QuestionType.YesNo))"></RadzenButton>
        <RadzenButton Text="@Localizer["FreeText"]" Style="width: 200px" Click="@(_ => OnQuestionTypeSelected(QuestionType.FreeText))"></RadzenButton>
      </RadzenStack>

    </RadzenStepsItem>
    <RadzenStepsItem Text="@Localizer["QuestionDetail"]">
      @switch (selectedQuestionType)
      {
        case QuestionType.YesNo:
          <YesNo SurveySectionModelId="@SurveySectionModelId" SelectedQuestionType="@selectedQuestionType"/>
          break;
        case QuestionType.FreeText:
          <FreeText SurveySectionModelId="@SurveySectionModelId" SelectedQuestionType="@selectedQuestionType"/>
          break;
        default:
          throw new ArgumentOutOfRangeException();
      }

    </RadzenStepsItem>
  </Steps>
</RadzenSteps>

@code {

  [Parameter]
  public Guid SurveySectionModelId { get; set; }

  public int selectedIndex;

  private QuestionType selectedQuestionType;

  private void OnQuestionTypeSelected(QuestionType questionType)
  {
    selectedQuestionType = questionType;
    selectedIndex = 1;
  }

}

YesNo.Razor:

<RadzenStack Orientation="Orientation.Vertical" JustifyContent="JustifyContent.Start" Gap="0.25rem">
  <RadzenStack Orientation="Orientation.Horizontal" JustifyContent="JustifyContent.SpaceBetween" Gap="0.25rem">
    <h3>@Localizer["YesNoQuestion"]</h3>
    <RadzenStack Orientation="Orientation.Vertical" AlignItems="AlignItems.End">
      <SwitchesQuestion QuestionModel="@QuestionModel" OnSwitchesChanged="SaveSwitches"/>
    </RadzenStack>
  </RadzenStack>
</RadzenStack>

<hr/>

<RadzenStack Orientation="Orientation.Vertical" JustifyContent="JustifyContent.Start" Gap="0.75rem">
  <TitleTooltipQuestion QuestionModel="@QuestionModel" OnTitleTooltipChanged="SaveTitleTooltip"/>
  <RadzenStack Gap="0.25rem">
    <RadzenLabel Text="Score" Component="Score"/>
    <RadzenRow AlignItems="AlignItems.Center">
      <RadzenColumn Size="12" SizeMD="1">
        <RadzenLabel Text="@Localizer["Yes"]" Component="Yes"/>
      </RadzenColumn>
      <RadzenColumn Size="12" SizeMD="2">
        <RadzenNumeric Name="ScoreYes" Min="0" ShowUpDown="false" @bind-Value="@QuestionModel.ScoreYes"/>
      </RadzenColumn>
    </RadzenRow>
    <RadzenRow AlignItems="AlignItems.Center">
      <RadzenColumn Size="12" SizeMD="1">
        <RadzenLabel Text="@Localizer["No"]" Component="Yes"/>
      </RadzenColumn>
      <RadzenColumn Size="12" SizeMD="2">
        <RadzenNumeric Name="ScoreNo" Min="0" ShowUpDown="false" @bind-Value="@QuestionModel.ScoreNo"/>
      </RadzenColumn>
    </RadzenRow>
  </RadzenStack>
</RadzenStack>
<SaveCancelQuestion SurveySectionModelId="@SurveySectionModelId" SelectedQuestionType="@SelectedQuestionType" QuestionModel="@QuestionModel"/>

@code {

  [Parameter]
  public QuestionModel QuestionModel { get; set; } = new();

  [Parameter]
  public Guid SurveySectionModelId { get; set; }


  [Parameter]
  public QuestionType SelectedQuestionType { get; set; }

  private void SaveSwitches(QuestionModel switchedQuestionModel)
  {
    QuestionModel.IsMandatory = switchedQuestionModel.IsMandatory;
    QuestionModel.NeedsProof = switchedQuestionModel.NeedsProof;
  }

  private void SaveTitleTooltip(QuestionModel changedQuestionModel)
  {
    QuestionModel.Title = changedQuestionModel.Title;
    QuestionModel.Tooltip = changedQuestionModel.Tooltip;
  }

}

TitleTooltipQuestion.razor:

<RadzenStack Orientation="Orientation.Vertical" AlignItems="AlignItems.Start" Gap="0.25rem">
  <RadzenLabel Text="@Localizer["Question"]" Component="Title"/>
  <RadzenTextArea Name="Title" @bind-Value="@QuestionModel.Title" Change="@(args => OnTitleEntered(args, "TitleText"))" class="w-100"/>
  <RadzenRequiredValidator Component="Title" Text="@Localizer["Required"]"/>
</RadzenStack>
<RadzenStack Orientation="Orientation.Vertical" AlignItems="AlignItems.Start" Gap="0.25rem">
  <RadzenLabel Text="@Localizer["Tooltip"]" Component="Tooltip"/>
  <RadzenTextArea Name="Tooltip" @bind-Value="@QuestionModel.Tooltip" Change="@(args => OnTooltipEntered(args, "TooltipText"))" class="w-100"/>
</RadzenStack>

@code {

  [Parameter]
  public EventCallback<QuestionModel> OnTitleTooltipChanged { get; set; }

  [Parameter]
  public QuestionModel QuestionModel { get; set; }

  private async Task OnTitleEntered(string value, string name)
  {
    QuestionModel.Title = value;
    await OnTitleTooltipChanged.InvokeAsync(QuestionModel);
  }

  private async Task OnTooltipEntered(string value, string name)
  {
    QuestionModel.Tooltip = value;
    await OnTitleTooltipChanged.InvokeAsync(QuestionModel);
  }

}

SaveCancelQuestion.razor:

<RadzenStack Orientation="Orientation.Horizontal" JustifyContent="JustifyContent.End" Gap="1rem" Class="rz-mt-2 rz-mb-2">
  <RadzenButton ButtonStyle="ButtonStyle.Primary" Size="ButtonSize.Medium" Icon="save" Text="@Localizer["Save"]" Click="@Save"/>
  <RadzenButton ButtonStyle="ButtonStyle.Secondary" Size="ButtonSize.Medium" Variant="Variant.Flat" Icon="cancel" Text="@Localizer["Cancel"]" Click="@Cancel"/>
</RadzenStack>

@code {

  [Parameter]
  public Guid SurveySectionModelId { get; set; }

  [Parameter]
  public QuestionModel QuestionModel { get; set; }

  [Parameter]
  public QuestionType SelectedQuestionType { get; set; }

  private void Save()
  {
    if (QuestionModel.SurveySectionModelId == Guid.Empty)
      QuestionModel.SurveySectionModelId = SurveySectionModelId;
    if (QuestionModel.QuestionType == QuestionType.Default)
      QuestionModel.QuestionType = SelectedQuestionType;
    DialogService.Close(QuestionModel);
  }

  private void Cancel()
  {
    DialogService.Close();
  }

}

I'm wondering where I need to put my RadzenTemplateForm, and also how I can trigger the RequiredValidator from within the SaveCancelQuestion component.

You can use the linked thread as a basis and start building from there. I am not sure if you have tried it yet.

Hi @korchev,

I've wrapped my YesNo.razor in a RadzenTemplateForm as mentioned.

<RadzenTemplateForm TItem="QuestionModel" Date = @QuestionModel>
<RadzenStack Orientation="Orientation.Vertical" JustifyContent="JustifyContent.Start" Gap="0.25rem">
  <RadzenStack Orientation="Orientation.Horizontal" JustifyContent="JustifyContent.SpaceBetween" Gap="0.25rem">
    <h3>@Localizer["YesNoQuestion"]</h3>
    <RadzenStack Orientation="Orientation.Vertical" AlignItems="AlignItems.End">
      <SwitchesQuestion QuestionModel="@QuestionModel" OnSwitchesChanged="SaveSwitches"/>
    </RadzenStack>
  </RadzenStack>
</RadzenStack>

<hr/>

<RadzenStack Orientation="Orientation.Vertical" JustifyContent="JustifyContent.Start" Gap="0.75rem">
  <TitleTooltipQuestion QuestionModel="@QuestionModel" OnTitleTooltipChanged="SaveTitleTooltip"/>
  <RadzenStack Gap="0.25rem">
    <RadzenLabel Text="Score" Component="Score"/>
    <RadzenRow AlignItems="AlignItems.Center">
      <RadzenColumn Size="12" SizeMD="1">
        <RadzenLabel Text="@Localizer["Yes"]" Component="Yes"/>
      </RadzenColumn>
      <RadzenColumn Size="12" SizeMD="2">
        <RadzenNumeric Name="ScoreYes" Min="0" ShowUpDown="false" @bind-Value="@QuestionModel.ScoreYes"/>
      </RadzenColumn>
    </RadzenRow>
    <RadzenRow AlignItems="AlignItems.Center">
      <RadzenColumn Size="12" SizeMD="1">
        <RadzenLabel Text="@Localizer["No"]" Component="Yes"/>
      </RadzenColumn>
      <RadzenColumn Size="12" SizeMD="2">
        <RadzenNumeric Name="ScoreNo" Min="0" ShowUpDown="false" @bind-Value="@QuestionModel.ScoreNo"/>
      </RadzenColumn>
    </RadzenRow>
  </RadzenStack>
</RadzenStack>
<SaveCancelQuestion SurveySectionModelId="@SurveySectionModelId" SelectedQuestionType="@SelectedQuestionType" QuestionModel="@QuestionModel"/>
</RadzenTemplateForm>

@code {

  [Parameter]
  public QuestionModel QuestionModel { get; set; } = new();

  [Parameter]
  public Guid SurveySectionModelId { get; set; }

  [Parameter]
  public QuestionType SelectedQuestionType { get; set; }

  private void SaveSwitches(QuestionModel switchedQuestionModel)
  {
    QuestionModel.IsMandatory = switchedQuestionModel.IsMandatory;
    QuestionModel.NeedsProof = switchedQuestionModel.NeedsProof;
  }

  private void SaveTitleTooltip(QuestionModel changedQuestionModel)
  {
    QuestionModel.Title = changedQuestionModel.Title;
    QuestionModel.Tooltip = changedQuestionModel.Tooltip;
  }

}

Then I added the RadzenRequiredValidator to my TitleTooltipQuestion.razor:

<RadzenStack Orientation="Orientation.Vertical" AlignItems="AlignItems.Start" Gap="0.25rem">
  <RadzenLabel Text="@Localizer["Question"]" Component="Title"/>
  <RadzenTextArea Name="Title" @bind-Value="@QuestionModel.Title" Change="@(args => OnTitleEntered(args, "TitleText"))" class="w-100"/>
  <RadzenRequiredValidator Component="Title" Text="@Localizer["Required"]"/>
</RadzenStack>
<RadzenStack Orientation="Orientation.Vertical" AlignItems="AlignItems.Start" Gap="0.25rem">
  <RadzenLabel Text="@Localizer["Tooltip"]" Component="Tooltip"/>
  <RadzenTextArea Name="Tooltip" @bind-Value="@QuestionModel.Tooltip" Change="@(args => OnTooltipEntered(args, "TooltipText"))" class="w-100"/>
</RadzenStack>

@code {

  [Parameter]
  public EventCallback<QuestionModel> OnTitleTooltipChanged { get; set; }

  [Parameter]
  public RequiredValidatorConfig.Model QuestionModel { get; set; }

  private async Task OnTitleEntered(string value, string name)
  {
    QuestionModel.Title = value;
    await OnTitleTooltipChanged.InvokeAsync(QuestionModel);
  }

  private async Task OnTooltipEntered(string value, string name)
  {
    QuestionModel.Tooltip = value;
    await OnTitleTooltipChanged.InvokeAsync(QuestionModel);
  }

}

However the code doesn't recognize RequiredValidatorConfig. Am I missing something?

I don't see anything obvious. I suggest you start from something that works and build up from there. The linked thread is a good starting point.

@korchev,

Sorry for the noob questions but in that thread, you give an example. In that example you mention to use RequiredValidatorConfig.Model. Where does the RequiredValidatorConfig come from?

That is just a namespace.