I have a custom validator that checks for input value that conflicts with existing ones. The validator works from components but fails to catch conflicts when used from pages - that's the only difference I can tell. However RadzenRequiredValidator works correctly in either case, so my custom validator must be missing something.
I include the code of the validator, and usages from component and page. The Radzen.Blazor version is 4.5.0.
Custom validator:
public class ExistenceValidator : ValidatorBase
{
[Parameter]
public override string Text { get; set; }
[Parameter]
public string CurrentName { get; set; }
[Parameter]
public IEnumerable<string> ExistingNames { get; set; }
/// <inheritdoc />
protected override bool Validate(IRadzenFormComponent component)
{
if (ExistingNames.IsNullOrEmpty())
return true;
var newName = (string)component.GetValue();
return !CurrentName.IsNullOrEmpty() && CurrentName == newName || !ExistingNames.Contains(newName);
}
}
Usage from a component:
@using CSG.ACPxOpsHub.Common.DataModel
@namespace CSG.ACPxOpsHub.Portal.Shared
@inject DialogService DialogService
@inject NavigationManager NavigationManager
<RadzenTemplateForm TItem="Group" Data="@_group" Submit="@Submit">
<RadzenFieldset Text="@Title">
<table class="form-basic" style="width: 100%">
<tr>
<th>
<RadzenLabel Text="Name" />
</th>
<td class="editable">
<RadzenTextBox Name="GroupName" @bind-Value="@_group.Name" style="width: 100%"/>
<RadzenRequiredValidator Component="GroupName" Text="Enter a group name."/>
<ExistenceValidator Component="GroupName" CurrentName="@Name" ExistingNames="@ExistingNames" Text="The group name already exists."/>
</td>
</tr>
<tr>
<th>
<RadzenLabel Text="Description" />
</th>
<td class="editable">
<RadzenTextBox @bind-Value="@_group.Description" style="width: 100%" />
</td>
</tr>
</table>
</RadzenFieldset>
<div class="col-md-12 d-flex align-items-end justify-content-center" style="margin-top: 16px;">
<RadzenButton ButtonStyle="ButtonStyle.Light" Icon="cancel" style="display: inline-block; margin-left: 10px;" Text="Cancel" Click="@Cancel"/>
<RadzenButton ButtonType="ButtonType.Submit" Text="Save" Icon="save" />
</div>
</RadzenTemplateForm>
@code
{
[Parameter]
public string Title { get; set; }
[Parameter]
public string Name { get; set; }
[Parameter]
public string Description { get; set; }
[Parameter]
public string[] ExistingNames { get; set; }
[Parameter]
public string PagePath { get; set; }
[Parameter]
public Action<string, string> Save { get; set; }
class Group
{
public string Name { get; set; }
public string Description { get; set; }
}
private Group _group;
protected override void OnParametersSet()
{
_group = new Group { Name = Name, Description = Description };
if (PagePath.IsNullOrEmpty())
PagePath = Constants.BlankPath;
}
void Cancel()
{
NavigationManager.NavigateTo(PagePath);
}
void Submit()
{
Save(_group.Name, _group.Description);
NavigationManager.NavigateTo(PagePath);
}
}
Usage from a page:
@attribute [Route("/" + Constants.AuthorizationAdminPath + "/{authorizationId:int?}")]
@using CSG.ACPxOpsHub.Portal.Services
@using CSG.ACPxOpsHub.Common.DataModel
@using CSG.Framework.Objects
@inject DialogService DialogService
@inject NavigationManager NavigationManager
@inject AuthorizationService AuthorizationService
<RadzenTemplateForm TItem="Authorization" Data="@_authorization" Submit="@Submit">
<RadzenFieldset>
<table class="form-basic" style="width: 100%">
<tr>
<th>
<RadzenLabel Text="Name" />
</th>
<td class="editable">
<RadzenTextBox Name="AuthName" @bind-Value="@_authorization.Name" style="width: 100%" />
<RadzenRequiredValidator Component="AuthName" Text="Enter a domain-qualified user or group name, e.g. CSGICORP\g_team_legend." />
<ExistenceValidator Component="AuthName" CurrentName="@_authorization.Name" ExistingNames="@_existingNames" Text="The user/group name already exists." />
</td>
</tr>
<tr>
<th>
<RadzenLabel Text="Type" />
</th>
<td class="editable">
<RadzenRadioButtonList @bind-Value=@_authorization.IsGroup TValue="bool">
<Items>
<RadzenRadioButtonListItem Text="Group" Value="true" />
<RadzenRadioButtonListItem Text="User" Value="false" />
</Items>
</RadzenRadioButtonList>
</td>
</tr>
</table>
</RadzenFieldset>
<div class="col-md-12 d-flex align-items-end justify-content-center" style="margin-top: 16px;">
<RadzenButton ButtonStyle="ButtonStyle.Light" Icon="cancel" style="display: inline-block; margin-left: 10px;" Text="Cancel" Click="@Cancel" />
<RadzenButton ButtonType="ButtonType.Submit" Text="Save" Icon="save" />
</div>
</RadzenTemplateForm>
@code
{
[Parameter]
public int? AuthorizationId { get; set; }
private string _pagePath;
private Authorization _authorization = new() {Id = -1};
private HashSet<string> _existingNames;
protected override void OnParametersSet()
{
_existingNames = new HashSet<string>(AuthorizationService.GetAllAuthorizations().Select(x => x.Name), StringComparer.CurrentCultureIgnoreCase);
if (!AuthorizationId.HasValue)
return;
_pagePath = $"{Constants.AuthorizationPath}/{AuthorizationId.Value}";
_authorization = (Authorization)AuthorizationService.GetAuthorization(AuthorizationId.Value).DeepClone();
}
void Submit()
{
// For some reason the ExistenceValidator fails to stop duplicated value, so we need to check here.
if (_existingNames.Contains(_authorization.Name))
DialogService.Alert($"{_authorization.Name} already exists.", "warning");
// Deep clone so that temporarily edits do not affect cached data objects.
var entry = (Authorization)_authorization.DeepClone();
AuthorizationService.SaveAuthorization(entry);
_pagePath = $"{Constants.AuthorizationPath}/{entry.Id}";
NavigationManager.NavigateTo(_pagePath);
}
void Cancel()
{
NavigationManager.NavigateTo(_pagePath);
}
}