My project is a Blazor server application. The fuctionality I am trying to achieve is I want my accordion header to change to the color red if my validation fails (if there is nothing in my input).
//my index.razor page:
@page "/"
<style>
</style>
<PageTitle>Blazor Bootstrap - Home</PageTitle>
<div class="test1">
<EditForm Model="@registration" OnValidSubmit="HandleFormSubmission">
<DataAnnotationsValidator />
<Accordion>
<AccordionItem Title="Accordion Item #1">
<Content>
<InputText id="SmtpHost" @bind-Value="@registration.SmtpHost" placeholder="SMTP Host" />
<ValidationMessage For="@(() => registration.SmtpHost)" />
</Content>
</AccordionItem>
</Accordion>
<button type="submit">Submit</button>
</EditForm>
</div>
@code {
[Inject]
protected IJSRuntime JSRuntime { get; set; }
Data.Registration registration = new();
bool isValidationError = false;
bool isFormSubmitted = false;
bool hasRendered = false;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// await Task.Yield();
// await ToggleAccordionButtonError();
}
}
public async Task HandleFormSubmission(EditContext context)
{
Console.WriteLine("Form Submitted Successfully");
isValidationError = !context.Validate();
Console.WriteLine("Testing");
Console.WriteLine(isValidationError);
if (isValidationError)
{
isFormSubmitted = true;
if (hasRendered)
{
ToggleAccordionButtonError();
}
else
{
StateHasChanged(); // Notify Blazor to re-render the component
}
}
}
private async Task ToggleAccordionButtonError()
{
try
{
await JSRuntime.InvokeVoidAsync("toggleAccordionButtonError");
await JSRuntime.InvokeVoidAsync("myJavaScriptFunction");
}
catch (Exception ex)
{
Console.WriteLine($"Error invoking JavaScript function: {ex.Message}");
}
}
}
my custom.js file:
console.log("File recognised");
function myJavaScriptFunction() {
// Invoke an alert
console.log("Hello from JavaScript!");
}
// .test1 .accordion-button
function toggleAccordionButtonError() {
console.log("Hello from JavaScript!");
var elements = document.querySelectorAll('.accordion-button.collapsed');
elements.forEach(function (element) {
element.style.backgroundColor = "red";
element.style.color = "white";
});
}
My custom.js does work I am aware I have commented out my code
One solution , I thought of was to use Javascript interobilty with HandleFormSubmission ;however it does'nt seem to work
I do know of Blazor's Prerendering is a feature in Blazor that allows components to be rendered on the server before being sent to the client, and it imposes certain restrictions on when JavaScript interop calls can be made. Is there a way around this issue . Any insight will be highly appreciated.
You can do something as simple as:
<AccordionItem class="@_accordianCss" Title="Accordion Item #1">
private string _accordianCss => isValidationError ? "accordian-invalid" : "accordian-valid";
And then add the styles either to your global css or isolated css.
You can also do something similar to open/collapse the accordian if you wish.
No JS required.
Here's a simple demo page using the build in bootstrap "invalid" css styling.
@page "/"
@using Microsoft.AspNetCore.Components.Forms
@using System.ComponentModel.DataAnnotations;
<div class="@_validationCss p-4 m-2">
<EditForm EditContext="_editContext" OnSubmit="@OnSubmitHandler">
<DataAnnotationsValidator />
<div>
<label class="form-label" >Enter name: </label>
<InputText class="form-control" id="name" @bind-Value="_customer.Name" /><br />
<ValidationMessage For="@(() => _customer.Name)" />
</div>
<div class="text-end mb-2">
<button class="btn btn-primary" type="submit">submit</button>
</div>
</EditForm>
</div>
<div class="alert @(_validated ? "alert-success" : "alert-danger")">
<p>Model valid: @_validated.ToString()</p>
</div>
@code {
private EditContext? _editContext;
private Customer _customer = new();
private bool _validated = true;
private string _validationCss => _validated ? "modified valid" : "invalid";
protected override void OnInitialized()
{
_customer = new Customer();
_editContext = new(_customer);
_editContext.OnValidationStateChanged += this.OnValidationStateChanged;
}
private void OnValidationStateChanged( object? sender, ValidationStateChangedEventArgs e )
{
if (_editContext is not null)
_validated = _editContext.GetValidationMessages().Count() == 0;
// This is an event so there's no built in call to StateHasChanged
this.StateHasChanged();
}
private void OnSubmitHandler()
{
_validated = _editContext?.Validate() ?? false;
}
public class Customer
{
[Required] public string? Name { get; set; }
}
}