I'm trying to separate different steps with form validation into different components. So, for example, the user fills in one step with personal information and the next step the user must fill in about education.
How will you solve this?
Right now, I have a trial period at Telerik, so I follow their Wizard component with form integration.
Error
Error: System.NullReferenceException: Object reference not set to an instance of an object. at Telerik.Blazor.Components.TelerikForm.IsValid() at ApplicantTemp.Pages.Wizard.MainComponent.OnRegistrationStepChange(WizardStepChangeEventArgs args) in C:\source\ApplicantSln\ApplicantTemp\Pages\Wizard\MainComponent.razor:line 50 at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr) --- End of stack trace from previous location --- at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task) at Telerik.Blazor.Components.Common.BaseComponent.InvokeEvent[T](EventCallback`1 eventCallback, T args) at Telerik.Blazor.Components.TelerikWizard.ChangeStep(Int32 newStepIndex) at Telerik.Blazor.Components.TelerikWizard.GoToNextPage() at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task) at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
public void OnRegistrationStepChange(WizardStepChangeEventArgs args)
{
// Add debugging code to inspect the state of RegisterForm and other variables
Console.WriteLine("OnRegistrationStepChange is called.");
Console.WriteLine($"RegisterForm is {RegisterForm}");
var isFormValid = RegisterForm.IsValid(); //ERROR FROM HERE!!!!!!!!
if (!isFormValid)
{
IsRegistrationValid = false;
args.IsCancelled = true;
}
else
{
IsRegistrationValid = true;
}
}
MainComponent.razor
@page "/reg"
@using System.ComponentModel.DataAnnotations
<TelerikWizard @bind-Value="@Value" OnFinish="@OnFinishHandler" Width="700px">
<WizardSteps>
<WizardStep Label="Registration" Icon="@FontIcon.User" OnChange="@OnRegistrationStepChange" Valid="@IsRegistrationValid">
<Content>
<RegistrationForm UserModel="@UserModel" RegisterForm="@RegisterForm" />
</Content>
</WizardStep>
<WizardStep Label="Shipping address" Icon="@FontIcon.MapMarkerTarget" OnChange="@OnShippingStepChange" Valid="@IsShippingValid">
<Content>
<ShippingForm ShippingModel="@ShippingModel" ShippingForm="@ShippingForm" />
</Content>
</WizardStep>
<WizardStep Label="Confirmation">
<Content>
<h2>Registration completed.</h2>
</Content>
</WizardStep>
</WizardSteps>
</TelerikWizard>
@code {
async Task OnFinishHandler()
{
ShowWizard = false;
await Dialog.AlertAsync("The Registration was submitted successfully", "Done");
}
protected override void OnInitialized()
{
// Add debugging code to inspect the state of RegisterForm
Console.WriteLine("MainComponent is being initialized.");
Console.WriteLine($"RegisterForm is {RegisterForm}");
}
public bool? IsRegistrationValid { get; set; }
public bool? IsShippingValid { get; set; }
[CascadingParameter]
public DialogFactory Dialog { get; set; }
public bool ShowWizard { get; set; } = true;
public int Value { get; set; }
public TelerikForm RegisterForm { get; set; } = new TelerikForm();
public UserPerson UserModel { get; set; } = new UserPerson();
public TelerikForm ShippingForm { get; set; }
public ShippingDetails ShippingModel { get; set; } = new ShippingDetails();
public void OnRegistrationStepChange(WizardStepChangeEventArgs args)
{
// Add debugging code to inspect the state of RegisterForm and other variables
Console.WriteLine("OnRegistrationStepChange is called.");
Console.WriteLine($"RegisterForm is {RegisterForm}");
var isFormValid = RegisterForm.IsValid();
if (!isFormValid)
{
IsRegistrationValid = false;
args.IsCancelled = true;
}
else
{
IsRegistrationValid = true;
}
}
public void OnShippingStepChange(WizardStepChangeEventArgs args)
{
// Add debugging code to inspect the state of ShippingForm and other variables
Console.WriteLine("OnShippingStepChange is called.");
Console.WriteLine($"ShippingForm is {ShippingForm}");
if (Value < args.TargetIndex)
{
var isFormValid = ShippingForm.IsValid();
if (!isFormValid)
{
IsShippingValid = false;
args.IsCancelled = true;
}
else
{
IsShippingValid = true;
}
}
}
public class UserPerson
{
[Required]
public string FirstName { get; set; } = "John";
[Required]
public string LastName { get; set; } = "Smith";
[Required]
public string Email { get; set; } = "[email protected]";
[MinLength(3, ErrorMessage = "The password should be at least 3 characters.")]
[Required]
public string Password { get; set; }
public DateTime? BirthDate { get; set; }
[Range(typeof(bool), "true", "true", ErrorMessage = "You must agree with the terms.")]
[Display(Name = "Accept Terms and Conditions")]
public bool AcceptTerms { get; set; }
}
public class ShippingDetails
{
[Required]
public string Country { get; set; }
[Required]
public string City { get; set; }
[Required]
public string AddressLine { get; set; }
public string AddressLine2 { get; set; }
}
}
RegistrationForm.razor
@using static ApplicantTemp.Pages.Wizard.MainComponent;
<!-- RegistrationForm.razor -->
@inherits UserFormBase
<TelerikForm Model="UserModel" @ref="RegisterForm">
<!-- Registration form content goes here -->
<FormValidation>
<DataAnnotationsValidator></DataAnnotationsValidator>
</FormValidation>
<FormItems>
<FormItem LabelText="First Name*:" Field="@nameof(UserModel.FirstName)"></FormItem>
<FormItem LabelText="Last Name*:" Field="@nameof(UserModel.LastName)"></FormItem>
<FormItem Field="@nameof(UserModel.Email)">
<Template>
<label for="mail" class="k-label k-form-label">Email*:</label>
<TelerikTextBox Id="mail" @bind-Value="@UserModel.Email" InputMode="email" PlaceHolder="[email protected]"></TelerikTextBox>
<TelerikValidationMessage For="@(() => UserModel.Email)"></TelerikValidationMessage>
</Template>
</FormItem>
<FormItem Field="@nameof(UserModel.Password)">
<Template>
<label for="pass" class="k-label k-form-label">Password*:</label>
<TelerikTextBox Id="pass" @bind-Value="@UserModel.Password" Password="true"></TelerikTextBox>
<TelerikValidationMessage For="@(() => UserModel.Password)"></TelerikValidationMessage>
</Template>
</FormItem>
<FormItem Field="@nameof(UserModel.AcceptTerms)" />
</FormItems>
<FormButtons></FormButtons>
</TelerikForm>
UserFormBase.razor
@using static ApplicantTemp.Pages.Wizard.MainComponent;
<!-- UserFormBase.razor -->
@inherits ComponentBase
@code {
[Parameter]
public UserPerson UserModel { get; set; }
[Parameter]
public TelerikForm RegisterForm { get; set; }
}