Home > Enterprise >  Blazor <InputSelect> inside <EditForm>?
Blazor <InputSelect> inside <EditForm>?

Time:03-15

I tried everything, Googled a lot, still can't get it to work. I'm trying to use <EditForm> with <InputSelect> to update an existing object(video in my case).

  1. I want an InputSelect with @bind-Value="video.DisplayId". Then the first selected option will be; either 1. if video.DisplayId is null, then display "None". 2. if video.DisplayId is not null, display the object's name (video.Display.Name).

  2. Then load the whole list of displays into options with foreach, except the currently selected.

  3. If video.DisplayId is not null then add an option at the end for "None".

When loading the Blazor page, everything looks fine with its values, and when I select i.e. from video.Display.Name to "None", and hit Save, it works.

But as soon as I go from "None" to a display.Name, it says Object reference not set to an instance of an object (see my code below, where it's saying it).

My code:

<InputSelect  @bind-Value="video.DisplayId">
    @if (video.DisplayId is null)
    {
        <option selected value="">None</option>
    }
    else 
    {
        // Object reference not set to an instance of an object ....
        <option selected value="@video.DisplayId">@video.Display.Name</option>
    }
    @foreach (Display display in displays.Where(display => display.Id != video.DisplayId))
    {
        <option value="@display.Id">@display.Name</option>
    }
    @if (video.DisplayId is not null)
    {
        <option value="">None</option>
    }
</InputSelect>

I think it has something to do with Blazor and how it's rendering the page after I select, but how do I fix this issue?

CodePudding user response:

@page "/"

<EditForm Model=@video>
    <InputSelect @[email protected]>
        @if (video.DisplayId is null)
        {
            <option value="">none</option>
        }
        else
        {
            <option value=@selectedDisplay?.Id>@selectedDisplay?.Name</option>
        }
        @foreach (var display in unSelectedDisplays)
        {
            <option [email protected]>@display.Name</option>
        }
        @if (video.DisplayId is not null)
        {
            <option value="">none</option>
        }
    </InputSelect>
</EditForm>

@code {
    private Video video = new Video();
    private IEnumerable<Display> displays = Enumerable.Empty<Display>();

    private IEnumerable<Display> unSelectedDisplays => 
        displays.Where(display => display.Id != video.DisplayId);

    Display? selectedDisplay => video.DisplayId.HasValue ?
                            displays.First(d => d.Id == this.video.DisplayId) :
                            default(Display);

    protected override void OnInitialized()
    {
        displays = Enumerable.Range(0, 10)
            .Select(i => new Display { Id = i, Name = $"Name{i}" });
    }

    public class Display
    {
        public int Id { get; set; }

        public string? Name { get; set; }
    }

    public class Video
    {
        public int? DisplayId { get; set; }
    }
}

CodePudding user response:

After many more hours, I figured it out. I needed to rewrite the code to following:

<InputSelect  @bind-Value="video.DisplayId">
    @if (video.DisplayId is null)
    {
        <option selected value="">None</option>
    }
    @foreach (Display display in displays)
    {
        <option value="@display.Id">@display.Name (ID: @display.Id)</option>
    }
    @if (video.DisplayId is not null)
    {
        <option value="">None</option>
    }
</InputSelect>

And after pressing Save, it calls my method, and inside my method it's changing the data inside the database, and then after that I had to Get the list again from the database.

  • Related