I have a form defined as follows :
@page "/booking"@rendermode RenderMode.InteractiveServer@using BlazorApp1.Models@using BlazorApp1.Services@inject IEntityService<Customer> CustomerService@inject IEntityService<ReservableItem> ReservableItemService@inject IEntityService<Reservation> ReservationService@inject NavigationManager NavigationManager<br /><div class="form-group booking-form"><br /><h2><b>Hi!</b></h2><p> Please enter your details along with estimated pickup and drop off time.<br />If you have any questions, please do not hesitate to reach out to us at</p></div><br /><div class="form-group booking-form"><br /><EditForm EditContext="editContext" OnValidSubmit="OnSubmitForm"><DataAnnotationsValidator></DataAnnotationsValidator><ValidationSummary></ValidationSummary><h2><b>Contact Info </b></h2><div><label label="form-label" for="name">Name:</label><InputText class="form-control" id="Name" @bind-Value="bookingInfo.c.Name" /><ValidationMessage For="@(() => bookingInfo.c.Name)"></ValidationMessage></div><div><label label="form-label" for="name">Email:</label><InputText class="form-control" id="Email" @bind-Value="bookingInfo.c.Email" /><ValidationMessage For="@(() => bookingInfo.c.Email)"></ValidationMessage></div><div><label label="form-label" for="name">Contact:</label><InputText class="form-control" id="phone1" @bind-Value="bookingInfo.c.PhoneNumber1" /><ValidationMessage For="@(() => bookingInfo.c.PhoneNumber1)"></ValidationMessage></div></EditForm><br /></div><br /><form class="booking-form" style="width:100%"><br /><h2><b>Pickup dates </b></h2> <div class="form-group" style="width:100%"><label for="pickup">Pickup (date & time)</label><input type="datetime-local" id="pickup" @bind="bookingInfo.r.ReservationStartingOn" class="form-control" /></div><div class="form-group"><label for="dropOff">Drop off (date & time)</label><input type="datetime-local" id="dropOff" @bind="bookingInfo.r.ReservationEndingOn" class="form-control" /></div><label>NOTE: Please provide time of pickup & drop off. Most of our bookings are single day. If you're interested in a multi-day booking, please call us at (</form><br /><form class="booking-form" style="width:100%"><h3> Select items for reservation </h3><br /><table class="table" width="100%"><thead><tr><th>Item Name</th><th>Description</th><th>Quantity</th></tr></thead><tbody> @foreach (var item in AvailableItems) {<tr><td>@item.ItemName</td><td>@item.ItemDescription</td><td><select @onchange="@((ChangeEventArgs args) => OnQuantityChanged(args, item.Id))" style="width: 60px; padding: 5px; font-size: 14px; border-radius: 4px; border: 1px solid #ccc; background-color: #f9f9f9; cursor: pointer;"> @for (int i = 0; i <= 40; i++) {<option value="@i">@i</option> }</select></td> @* <td><input type="number" @onchange="@((ChangeEventArgs args) => OnQuantityChanged(args, item.Id))" class="quantity-input" /></td> *@</tr> }</tbody></table><button type="button" class="submit-button" @onclick="OnSubmitForm">Submit</button></form>@code { private EditContext? editContext; private List<ReservableItem> AvailableItems { get; set; } = new List<ReservableItem>(); private BookingInfo bookingInfo { get; set; } = new BookingInfo(); class BookingInfo { public Customer c = new Customer(); public Reservation r = new Reservation(); } public Booking() { bookingInfo = new BookingInfo(); bookingInfo.r.ReservationStartingOn = DateTime.Now; bookingInfo.r.ReservationEndingOn = DateTime.Now + TimeSpan.FromDays(1.0); } protected override void OnInitialized() { base.OnInitialized(); AvailableItems = ReservableItemService.GetAll(); editContext = new(bookingInfo); } private void OnQuantityChanged(ChangeEventArgs args, int id) { var item = AvailableItems.FirstOrDefault(it => it.Id == id); var bookedReservedItem = bookingInfo.r.ReservedItems?.FirstOrDefault(rr => rr.ReservableItem != null && rr.ReservableItem.Id == item.Id); if (bookedReservedItem == null) { ReservedItem reservedItem = new ReservedItem { ReservableItem = item, Quantity = int.TryParse(args?.Value?.ToString(), out int result) ? result : 0 }; bookingInfo.r.ReservedItems.Add(reservedItem); } else { bookedReservedItem.Quantity = int.TryParse(args?.Value?.ToString(), out int result) ? result : 0; } } private void OnSubmitForm() { try { CustomerService.AddEntity(bookingInfo.c); bookingInfo.r.CustomerID = bookingInfo.c.Id; bookingInfo.r.ReservationCreatedOn = DateTime.Now; CreateReservation(bookingInfo.r); NavigationManager.NavigateTo("bookingcompleted"); } catch { NavigationManager.NavigateTo("Error"); } } private void CreateReservation(Reservation reservation) { using (var _ctx = ReservationService.GetDbContext()) { foreach (var item in reservation.ReservedItems) { _ctx.Attach(item.ReservableItem); } _ctx.Add(reservation); _ctx.SaveChanges(); } }}The entity bookingInfo.c is defined as follows:
public class Customer { [Required] [MaxLength(50, ErrorMessage = "Name is too long")] [MinLength(4, ErrorMessage = "Name is too short")] public string Name { get; set; } [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } [Range(10,100, ErrorMessage = "Invalid age")] public int Age { get; set; } public DateTime CreatedDate { get; set; } [Required] [Phone] public string PhoneNumber1 { get; set; } [Phone] public string PhoneNumber2 { get; set; } [Required] [EmailAddress] public string Email { get; set; } public DateTime DateFirstContacted { get; set; } }The issue is that OnSubmitForm fired when I hit submit, even though the values are null. The entities are annotated with Required and ranges, then how does it pass the validation ? Am I missing something here ?
EDIT: Updated and put the entire component code.