skip to Main Content

I have a Blazor component where I use an InputSelect to allow users to select a role for a user. The issue is that the @bind-Value of the InputSelect does not update the SelectedRole variable as expected. When I try to save the changes, the role that gets saved is the initially selected role, not the one chosen in the dropdown.

Here it is part of my code:

    <div class="row">
        <div class="col-md-4">
            <EditForm method="post" Model="User" OnValidSubmit="SaveChanges" FormName="EditUserForm">
                <DataAnnotationsValidator />
                <ValidationSummary role="alert" />

                <div class="mb-3">
                    <label for="username" class="form-label">Nome</label>
                    <InputText id="username" @bind-Value="User.UserName" class="form-control" readonly />
                </div>
                <div class="mb-3">
                    <label for="email" class="form-label">Email</label>
                    <InputText id="email" @bind-Value="User.Email" class="form-control" readonly />
                </div>
                <div class="mb-3">
                    <label for="role" class="form-label">Selecionar Role:</label>
                    <InputSelect id="role" @bind-Value="SelectedRole" class="form-group" >
                        <option value="-1">Nenhum</option>
                        @foreach (var role in AllRoles)
                        {
                            <option value="@role.Name">@role.Name</option>
                        }
                    </InputSelect>
                </div>

                <p>Selected Role: @SelectedRole</p>

                <button type="submit" class="btn btn-primary"><img title="Gravar" src="/img/saveicon.png" style="height:30px" /></button>
                <a href="/GereUsers" type="button" class="btn btn-outline-secondary"><img title="Recuar" src="/img/backicon.png" style="height:30px" /></a>
            </EditForm>
        </div>
    </div>
}

<p class="text-info">@DebugMessage</p>

@code {
    [SupplyParameterFromQuery]
    private string? Id { get; set; }
    private ApplicationUser? User;
    private List<IdentityRole> AllRoles = new();
    private string? SelectedRole;

    private string DebugMessage { get; set; } = "Inicializando...";

    protected override async Task OnInitializedAsync()
    {

        if (Id is not null)
        {
            User = await UserManager.FindByIdAsync(Id);

            if (User is null)
            {
                DebugMessage = "Usuário não encontrado.";
                NavigationManager.NavigateTo("/notfound");
                return;
            }

            AllRoles = RoleManager.Roles.ToList();

            var roles = await UserManager.GetRolesAsync(User);

           
            SelectedRole = roles.FirstOrDefault() ?? "-1";
            

        }
    }

    private async Task SaveChanges()
    {

        if (User is not null)
        {
            if (string.IsNullOrEmpty(SelectedRole) || SelectedRole == "-1")
            {
                var currentRoles = await UserManager.GetRolesAsync(User);
                await UserManager.RemoveFromRolesAsync(User, currentRoles);
            }
            else
            {
                var currentRoles = await UserManager.GetRolesAsync(User);

                var rolesToRemove = currentRoles.Where(r => r != SelectedRole).ToList();
                await UserManager.RemoveFromRolesAsync(User, rolesToRemove);

                if (!currentRoles.Contains(SelectedRole))
                {
                    await UserManager.AddToRoleAsync(User, SelectedRole);
                }
            }

        }
    }

}

What I’ve Tried:

  1. Verified that the SelectedRole property is a string.
  2. Confirmed that AllRoles contains the correct data.
  3. Forced a value to SelectedRole directly before the if condition in the SaveChanges method, and the rest of the program works as expected, meaning the issue is isolated to the InputSelect not updating SelectedRole.

Expected Behavior:
The SelectedRole should update when a new role is selected from the dropdown, and the correct role should be saved when changes are submitted.

Actual Behavior:
The SelectedRole does not reflect the new selection, and the saved role remains as the initially loaded role.

How can I ensure that the InputSelect properly updates the SelectedRole variable?

2

Answers


  1. Based on

    • Net8
    • RenderMode: Server
    • Interactivity : Global

    I can’t see what’s wrong with your code, but it’s probably in the stuff you haven’t shown. Here’s a stripped down version of your code as a single page that works.

    @page "/"
    
    <PageTitle>Home</PageTitle>
    
    <div class="row">
        <div class="col-md-4">
            <EditForm method="post" Model="User" OnValidSubmit="SaveChanges" FormName="EditUserForm">
    
                <div class="mb-3">
                    <label for="username" class="form-label">Nome</label>
                    <InputText id="username" @bind-Value="User.UserName" class="form-control" readonly />
                </div>
                <div class="mb-3">
                    <label for="role" class="form-label">Selecionar Role:</label>
                    <InputSelect id="role" @bind-Value="SelectedRole" class="form-group">
                        @if(SelectedRole is null)
                        {
                            <option disabled selected value="">-- Select A Role --</option>
                        }
                        @foreach (var role in AllRoles)
                        {
                            <option value="@role.Name">@role.Name</option>
                        }
                    </InputSelect>
                </div>
    
                <p>Selected Role: @SelectedRole</p>
    
                <button type="submit" class="btn btn-primary"><img title="Gravar" src="/img/saveicon.png" style="height:30px" /></button>
                <a href="/GereUsers" type="button" class="btn btn-outline-secondary"><img title="Recuar" src="/img/backicon.png" style="height:30px" /></a>
            </EditForm>
        </div>
    </div>
    }
    
    <p class="text-info">@SelectedRole</p>
    
    @code {
        [SupplyParameterFromQuery]
        private string? Id { get; set; }
        private ApplicationUser User = new();
        private List<IdentityRole> AllRoles = new();
        private string? SelectedRole;
    
        protected override async Task OnInitializedAsync()
        {
            await Task.Yield();
    
            User = new ApplicationUser { UserName = "Tester" };
    
            AllRoles = new List<IdentityRole>
            {
                new IdentityRole("Admin"),
                new IdentityRole("User"),
                new IdentityRole("Guest")
            };
        }
    
        private async Task SaveChanges()
        {
        }
    
        public class ApplicationUser
        {
            public string? UserName { get; set; }
    
        }
    
        public readonly record struct IdentityRole(string Name);
    }
    
    Login or Signup to reply.
  2. Actual Behavior: The SelectedRole does not reflect the new selection,
    and the saved role remains as the initially loaded role.

    How can I ensure that the InputSelect properly updates the
    SelectedRole variable?

    Try to set a break point in the OnInitializedAsync method, you will find that after submitting the form, this method will execute first and then the SaveChanges method, so it will change the selected value to the default value.

    To solve this issue, you can check whether the SelectedRole is null or not in the OnInitializedAsync method, and then set the default value. Code like this:

    protected override async Task OnInitializedAsync()
    { 
        if (Id is not null)
        {
            User = await UserManager.FindByIdAsync(Id);
    
            if (User is null)
            {
                DebugMessage = "Usuário não encontrado.";
                NavigationManager.NavigateTo("/notfound");
                return;
            }
    
            AllRoles = RoleManager.Roles.ToList();
    
            var roles = await UserManager.GetRolesAsync(User);
    
            //if the SelectRole is null, set the default value.
            if (SelectedRole is null)
                SelectedRole = roles.FirstOrDefault() ?? "-1";
        }
    }
    

    Besides, since you will receive the data from the form. I think you’d better to add the [SupplyParameterFromForm] attribute for the User and SelectedRole, after modified the code should like this:

    [SupplyParameterFromForm]
    private ApplicationUser? User { get; set; } = new(); 
    [SupplyParameterFromForm]
    private string? SelectedRole { get; set; }
    

    After that in the SaveChanges method, you can see the selected value.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search