Search code examples
c#asp.net-coreweb-applicationsblazormatblazor

Blazor MatAutocompletelist throwing System.ArgumentNullException


I'm building hotel service web application and I'm want to use MatBlazor component called MatAutocompleteList for choosing clients for reservations I've encountered an issue when Client is selected like on the screen

enter image description here

And I remove this value leaving it blank and press enter application throws an exception: enter image description here

System.ArgumentNullException: Value cannot be null. (Parameter 'model')
   at Microsoft.AspNetCore.Components.Forms.FieldIdentifier..ctor(Object model, String fieldName)
   at Microsoft.AspNetCore.Components.Forms.FieldIdentifier.Create[TField](Expression`1 accessor)
   at Microsoft.AspNetCore.Components.Forms.ValidationMessage`1.OnParametersSet()
   at Microsoft.AspNetCore.Components.ComponentBase.CallOnParametersSetAsync()
   at Microsoft.AspNetCore.Components.ComponentBase.SetParametersAsync(ParameterView parameters)
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.SetDirectParameters(ParameterView parameters)

Heres the usage of a component:

@using HotelServiceSystem.Entities
@using HotelServiceSystem.Features
@using HotelServiceSystem.Interfaces.Services
@using HotelServiceSystem.Core
@inject IHotelReservationService hotelReservationService
@inject IClientService clientService
@inject IRoomService roomService

<EditForm Model="@ReservationModel" OnValidSubmit="@SaveReservation">
    <FluentValidationValidator/>
    @if (ClientList != null && ClientList.Any())
    {
            <MatAutocompleteList Items="@ClientList.ToArray()" TItem="Client" CustomStringSelector="@(i => i.FirstName + " " + i.LastName)" Label="Choose client" @bind-Value="@ReservationModel.Client" FullWidth="@true" ShowClearButton="@true">
                <ItemTemplate Context="template">
                    <div style="display: flex; flex-direction: row; width: 100%;">
                        <div>@template.FirstName @template.LastName @template.PhoneNumber</div>
                    </div>
                </ItemTemplate>
            </MatAutocompleteList>
    }
    else
    {
        <p>First u need to add clients</p>
    }
    <ValidationMessage For="@(()=> ReservationModel.Client.Id)"></ValidationMessage>
    <HssInputCustom Caption="Number of guests" @bind-Value="ReservationModel.NumberOfGuests"/>
    <div class="col-12 row">
        <label class="col-2">Date From</label>
        <MatDatePicker class="form-control col-3" @bind-Value="ReservationModel.DateFrom"/>
    </div>
    <div class="col-12 row">
        <label class="col-2">Date to</label>
        <MatDatePicker class="form-control col-3" @bind-Value="ReservationModel.DateTo"/>
        <ValidationMessage For="@(() => ReservationModel.DateTo)"></ValidationMessage>
    </div>
    <div class="form-group">
        <HSSMultiSelector Selected="@_selected" NotSelected="@_notSelected"/>
    </div>
    <HssInputCustom Caption="Price" @bind-Value="ReservationModel.Price"/>
    <HssInputCustom Caption="Discount" @bind-Value="ReservationModel.Discount"/>
    <div class="col-12 row">
        <span class="col-2"></span>
        <input type="submit" class="form-control col-1 btn btn-primary" value="Submit"/>
    </div>
</EditForm>

@code {
    private HotelReservation ReservationModel { get; set; }
    private readonly List<MultiSelector> _selected = new List<MultiSelector>();
    private List<MultiSelector> _notSelected = new List<MultiSelector>();
    private List<Room> _selectedRooms = new List<Room>();
    private List<Room> RoomList { get; set; }
    private List<Client> ClientList { get; set; }
    private List<string> ClientIdList { get; set; }

    [Parameter]
    public EventCallback<HotelReservation> OnReservationAdd { get; set; }

    protected override async Task OnInitializedAsync()
    {
        RoomList = roomService.GetAllRoomsAsync();
        ClientList = clientService.GetAllClients();
        ReservationModel = new HotelReservation {Client = new Client()};
        _notSelected = RoomList.Select(x => new MultiSelector(x.Id.ToString(), $"Room Number : {x.RoomIdentifier}")).ToList();
        await base.OnInitializedAsync();
    }
    

    private async Task SaveReservation()
    {
        _selectedRooms = RoomList.Where(x => _selected.Any(y => y.Key == x.Id.ToString())).ToList();

        _selectedRooms.ForEach( x=> ReservationModel.RoomReservations.Add(new RoomReservation
        {
            Reservation = ReservationModel,
            Room = x
        }));

        await hotelReservationService.AddHotelReservationAsync(ReservationModel);
        await OnReservationAdd.InvokeAsync(ReservationModel);
        ReservationModel = new HotelReservation() {Client = new Client()};
    }
}

Also my model to which I'm binding value is created properly.

 private Client _selectedClient = new Client();

I've no clue how I can prevent user from doing that, or if I can somehow catch this exception. Maybe someone had a similar issue. Much appriciate help!


Solution

  • I did manage to resolve this issue in simple way. I've created property for my model client object and in this propery I've created a null check

    private Client _selectedClient
    {
        get
        {
            if (ReservationModel.Client == null)
            {
                return new Client()
                {
                    CompanyName = "",
                    Email = "",
                    FirstName = "",
                    LastName = "",
                    PhoneNumber = "",
                    Id = 0
                };
            }
    
            return ReservationModel.Client;
    
        }
        set => ReservationModel.Client = value;
    }
    

    and now in code im calling property to set and get value for my model.