Quantcast
Channel: Active questions tagged blazor - Stack Overflow
Viewing all articles
Browse latest Browse all 4839

Conditionally handle multiple ValidationMessages with a ValidateComplexType model in an EditForm

$
0
0

In a Blazor web app, I needed to conditionally handle multiple <ValidationMessages> because they're not bound to a single function.

At the moment, I have two instances of <ValidationMessages>.

This is the algorithm I should achieve:

  • The first one should be executed on a button click to trigger a state change for this function.

    For example, a button is clicked, and state1 is true, and state2 is currently false.

    If I proceed, either the state1 function should be executed and the state2 function skipped, or vice versa.

  • It should handle the validation messages correspondingly with their particular functions.

But this isn't achieved on my current setup.

Data class model:

[Keyless]public class SomeModel{  [Required]  [ValidateComplexType]  public SomeOtherModel SomeOtherModel { get; set; }  [Required]  public string? SelectedRoleID { get; set; }  [Required(ErrorMessage = "Required field.")]  public string? SelectedRole { get; set; }  [Required]  public string? SelectedRemarkID { get; set; }  [Required(ErrorMessage = "Required field.")]  public string? SelectedRemark { get; set; }  public SomeModel() // for demonstration purposes only XD, I observed that it is not currently in use.  {    SomeOtherModel = new SomeOtherModel();  }}[Keyless]public class SomeOtherModel{  [Required]  public string? SomeField { get; set; }  // other fields here...}

Razor page

Client-side

@page "/users/review-user"@page "/users/review/{Id}/user"@rendermode InteractiveServer@using Microsoft.EntityFrameworkCore@using MyProject.Models.SQLServer@using MyProject.Data.SQLServer@implements IAsyncDisposable@inject IDbContextFactory<MyProject.Data.SQLServer.SQLServerContext> DbFactory@inject NavigationManager NavigationManager@inject IJSRuntime JS<PageTitle>Details</PageTitle><h3>Review User</h3><script src="lib/customjs/reviewuser.js"></script><div><hr />    @if (plainTextModel is null)    {<div class="position-absolute top-50 start-50 translate-middle"><div class="spinner-grow text-danger spinner-grow-xxl" role="status"><span class="visually-hidden">Loading...</span></div></div>    }    else    {<EditForm Model="SomeModel" OnValidSubmit="VerifyUser" FormName="reviewUser" Enhance><ObjectGraphDataAnnotationsValidator /><div class="container-fluid overflow-x-auto mw-40"><div class="row py-1 border rounded border-secondary-subtle text-center my-1"><!-- Left side: user info --><div class="col-6 d-flex flex-column justify-content-center align-items-center"><dl class="row m-0"><dt class="col-sm-3 text-start p-0">#</dt><dd class="col-sm-9">@rowNum</dd><dt class="col-sm-3 text-start p-0">Role</dt>                            @if (isModifyUser)                            {<dd class="col-sm-9">                                    @if (userRoles is null)                                    {<div class="position-absolute top-50 start-50 translate-middle"><div class="spinner-grow text-danger spinner-grow-sm" role="status"><span class="visually-hidden">Loading...</span></div></div>                                    }                                    else                                    {<Dropdown Color="DropdownColor.Light" Size="DropdownSize.Small"><DropdownToggleButton>@(SomeModel.SelectedRole ?? "Please select a role")</DropdownToggleButton><DropdownMenu>                                                @foreach (var role in userRoles)                                                {<DropdownItem @onclick="() => OnRoleItemSelected(role)" Active="@role.IsActive"                                                        Disabled="@(role.RoleType == "Programmer")">@role.RoleType</DropdownItem>                                                }</DropdownMenu></Dropdown><ValidationMessage For="() => SomeModel.SelectedRole" class="text-danger" />                                    }</dd>                            }                            else                            {<dd class="col-sm-9">@plainTextModel.RoleType</dd>                            }</dl>                        @if (isModifyUser || isReevaluateUser)                        {<div class="row py-1 text-center m-1 w-100"><div class="col-6 d-flex flex-column justify-content-center align-items-center ps-0"><button type="submit" class="btn btn-primary w-100 text-wrap">Save Changes</button></div><div class="col-6 d-flex flex-column justify-content-center align-items-center pe-0"><button @onclick="Discard" type="button"                                        class="btn btn-outline-danger w-100 text-wrap">Discard</button></div></div>                        }</div><!-- Right side: actions --><div class="col-6 d-flex flex-column justify-content-center align-items-center gap-3 py-3"><dl class="row m-0"><dt class="col-sm-3 text-start p-0">Remarks</dt>                            @if (isReevaluateUser)                            {<dd class="col-sm-9">                                    @if (userRemarks is null)                                    {<div class="position-absolute top-50 start-50 translate-middle"><div class="spinner-grow text-danger spinner-grow-sm" role="status"><span class="visually-hidden">Loading...</span></div></div>                                    }                                    else                                    {<Dropdown Color="DropdownColor.Light" Size="DropdownSize.Small" Class="w-100"><DropdownToggleButton Class="text-truncate">@(SomeModel.SelectedRemark ??"Please select a remark")</DropdownToggleButton><DropdownMenu data-bs-display="static">                                                @foreach (var remark in userRemarks)                                                {<DropdownItem @onclick="() => OnRemarkItemSelected(remark)">@remark.Remarks</DropdownItem>                                                }</DropdownMenu></Dropdown><ValidationMessage For="() => SomeModel.SelectedRemark" class="text-danger" />                                    }</dd>                            }                            else                            {                                @if (plainTextModel.Remarks == null)                                {<dd class="col-sm-9 fw-bold">-</dd>                                }                                else                                {<dd class="col-sm-9">@plainTextModel.Remarks</dd>                                }                            }</dl><button @onclick="ReevaluateUser" type="button" class="btn btn-danger w-100 text-wrap">Reevaluate                            User</button><button @onclick="ModifyUser" type="button" class="btn btn-warning w-100 text-wrap">Modify User                            Role</button></div></div>                @if (reviewUserListImageSingle is null)                {<div class="position-absolute top-50 start-50 translate-middle"><div class="spinner-grow text-danger spinner-grow-xxl" role="status"><span class="visually-hidden">Loading...</span></div></div>                }                else                {<div class="container-fluid p-0"><div class="row gap-2"><div class="col"><div class="row py-1 border rounded border-secondary-subtle text-center my-2">                                    @*other code here*@</div></div><div class="col"><div class="row py-1 border rounded border-secondary-subtle text-center my-2">                                    @*other code here*@</div></div><div class="col"><div class="row py-1 border rounded border-secondary-subtle text-center my-2">                                    @*other code here*@</div></div></div></div>                }</div></EditForm>    }</div><div id="liveToast" class="toast align-items-center text-bg-primary border-0 position-fixed bottom-0 end-0 mb-3 me-3"    role="alert" aria-live="assertive" aria-atomic="true" data-bs-delay="1500"><div class="d-flex"><div class="toast-body">            Successfully modified!</div><button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"            aria-label="Close"></button></div></div><div id="liveToastError"    class="toast align-items-center text-bg-danger border-0 position-fixed bottom-0 end-0 mb-3 me-3" role="alert"    aria-live="assertive" aria-atomic="true" data-bs-delay="1500"><div class="d-flex">        @if (errorMessage is not null)        {<div class="toast-body">                @errorMessage</div>        }        else        {<div class="toast-body">                Someting went wrong. Please try again later.</div>        }<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"            aria-label="Close"></button></div></div><div class="modal fade" id="verifyModal" data-bs-keyboard="false" tabindex="-1" aria-labelledby="verifyModalLabel"    aria-hidden="true"><div class="modal-dialog modal-sm"><div class="modal-content"><div class="modal-body">                Are you sure you want to verify this user?</div><div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button><EditForm method="post" Model="SomeModel" OnValidSubmit="VerifyUser" FormName="reviewUser"                    Enhance>                    @* <input type="hidden" name="ReturnUrl" value="@currentUrl" /> *@<button type="submit" class="btn btn-danger">Confirm</button></EditForm></div></div></div></div>

Server-side

@code {    private SomeModel SomeModel = new SomeModel();    private PlainTextModel? plainTextModel = new();    private UserListImageSingleDM? reviewUserListImageSingle = new();    private List<UserRoles>? userRoles = new();    private List<UserRemarks>? userRemarks = new();    private SQLServerContext context = default!;    [SupplyParameterFromQuery(Name = "status")]    private bool status { get; set; }    [SupplyParameterFromQuery(Name = "row")]    private long rowNum { get; set; }    [Parameter]    public string? Id { get; set; }    private bool isModifyUser = false;    private bool isReevaluateUser = false;    private string? errorMessage;    private string? output;    protected override async Task OnInitializedAsync()    {        context = DbFactory.CreateDbContext();        await LoadPlainText();    }    private async Task LoadPlainText()    {        var sQLServerHelper = new SQLServerHelper(context);        var spParamPlainText = SQLServerInnerHelper.GlobalMethodRazorPageParam(id: Id, key:"REVIEW_USER_PLAINTEXT");        plainTextModel = await sQLServerHelper.PlainTextAsync("myStoredProcedure", spParamPlainText);        // TODO: Let this load first.        if (plainTextModel is null)        {            NavigationManager.NavigateTo("notfound");        }        StateHasChanged();    }    private async Task ModifyUser()    {        SomeModel.SelectedRemark = null;        isModifyUser = true;        isReevaluateUser = false;        // data fetch for userRoles    }    private async Task ReevaluateUser()    {        SomeModel.SelectedRoleID = null;        SomeModel.SelectedRole = null;        isReevaluateUser = true;        isModifyUser = false;        // data fetch for userRemarks    }    private void Discard()    {        isModifyUser = false;        isReevaluateUser = false;    }    private void OnRoleItemSelected(UserRoles item)    {        SomeModel.SelectedRoleID = item.RoleID ?? string.Empty;        SomeModel.SelectedRole = item.RoleType ?? string.Empty;        SetActiveRole(SomeModel.SelectedRoleID);    }    private void OnRemarkItemSelected(UserRemarks item)    {        SomeModel.SelectedRemarkID = item.RemarkID ?? string.Empty;        SomeModel.SelectedRemark = item.Remarks ?? string.Empty;    }    private void SetActiveRole(string id)    {        if (userRoles is null) return;        foreach (var role in userRoles)            role.IsActive = role.RoleID == id;    }    private async Task VerifyUser()    {        if (isModifyUser)        {            var sQLServerHelper = new SQLServerHelper(context);            var spParam = SQLServerInnerHelper.ManageUsersDataWOutputPageParams(userID: Id, roleID:            SomeModel.SelectedRoleID, functionKey:"TEST_KEY_1");            output = await sQLServerHelper.StringOutputAsync("myStoredProcedure", spParam);            if (output is not null && output == "SUCCESSFUL")            {                await JS.InvokeVoidAsync("showLiveToast");            }            else if (output is not null && output != "SUCCESSFUL")            {                errorMessage = null;                await JS.InvokeVoidAsync("showLiveToastError");            }            else            {                errorMessage = null;                await JS.InvokeVoidAsync("showLiveToastError");            }        }        else if (isReevaluateUser)        {            var sQLServerHelper = new SQLServerHelper(context);            var spParam = SQLServerInnerHelper.ManageUsersDataWOutputPageParams(userID: Id, remarkID:            SomeModel.SelectedRemarkID, functionKey:"TEST_KEY_2");            output = await sQLServerHelper.StringOutputAsync("myStoredProcedure", spParam);            if (output is not null && output == "SUCCESSFUL")            {                await JS.InvokeVoidAsync("showLiveToast");            }            else if (output is not null && output != "SUCCESSFUL")            {                errorMessage = null;                await JS.InvokeVoidAsync("showLiveToastError");            }            else            {                errorMessage = null;                await JS.InvokeVoidAsync("showLiveToastError");            }        }        else        {            var sQLServerHelper = new SQLServerHelper(context);            var spParam = SQLServerInnerHelper.ManageUsersDataWOutputPageParams(userID: Id, userIDModifier: "DevQt",            functionKey:"TEST_KEY_3");            output = await sQLServerHelper.StringOutputAsync("myStoredProcedure", spParam);            if (output is not null && output == "SUCCESSFUL")            {                await JS.InvokeVoidAsync("showLiveToast");            }            else if (output is not null && output != "SUCCESSFUL")            {                errorMessage = null;                await JS.InvokeVoidAsync("showLiveToastError");            }            else            {                errorMessage = null;                await JS.InvokeVoidAsync("showLiveToastError");            }        }    }    public async ValueTask DisposeAsync() // this is important    {        await context.DisposeAsync();    }}

I was expecting this to run properly since it is conditionally managed through states: isModifyUser and isReevaluateUser. But it's not.

It works only if I commented out these classes (for demonstration purposes only):

<ObjectGraphDataAnnotationsValidator />
<ValidationMessage For="() => SomeModel.SelectedRole" class="text-danger" />
<ValidationMessage For="() => SomeModel.SelectedRemark" class="text-danger" />

But I needed those classes to implement validation in the simplest way possible.

The concept of my project is inspired by this thread:

Moreover, this portion of my Blazor web app project will serve as the main reference for its other modules.


Viewing all articles
Browse latest Browse all 4839

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>