Multiple Blazored Typeaheads within foreach

I'm using Blazored Typeahead within my Blazor server application. In my razor page following code

Blazored Typeahead - within Foreach

    @foreach (var employee in EmployeeList)
    {
        <div class="row">
            <div class="col-3">
                <BlazoredTypeahead SearchMethod="@GetPeopleLocal"
                               @bind-Value="@SelectedPerson"
                               placeholder="Search by first name...">
                    <SelectedTemplate Context="person">
                        @person.Firstname
                    </SelectedTemplate>
                    <ResultTemplate Context="person">
                        @person.Firstname @person.Lastname
                    </ResultTemplate>
                </BlazoredTypeahead>
            </div>
            <div class="col-3">
                <BlazoredTypeahead SearchMethod="@GetRolesLocal"
                               @bind-Value="@SelectedRole"
                               placeholder="Search by role name...">
                    <SelectedTemplate Context="role">
                        @role.Rolename
                    </SelectedTemplate>
                    <ResultTemplate Context="role">
                        @role.Rolename
                    </ResultTemplate>
                </BlazoredTypeahead>
            </div>
            <div class="col-1">
                <a href="javascript:void(0)" class="btn btn-danger" @onclick="@(()=>OnEmployeeDelete(employee))">X</a>
            </div>
        </div>
    }
    
    <div class="form-group">
        <a href="javascript:void(0)" class="btn btn-success" @onclick="@(()=>OnEmployeeAdd())">Add Employee</a>
    </div>
    
    <div class="form-group">
        <a href="javascript:void(0)" class="btn btn-success" @onclick="@(()=>CreateEmployeeList())">Create Employee List</a>
    </div>


@code {
    private List<Employee> EmployeeList = new List<Employee>();
    private Employee employee = new Employee();

    private List<Person> People = new List<Person>();
    private List<Role> Roles = new List<Role>();
    private Person SelectedPerson;
    private Role SelectedRole;

    protected override void OnInitialized()
    {
        People.AddRange(new List<Person>()
            {
                    new Person() { Id = 1, Firstname = "Martelle", Lastname = "Cullon" },
                    new Person() { Id = 2, Firstname = "Zelda", Lastname = "Abrahamsson" },
                    new Person() { Id = 3, Firstname = "Benedetta", Lastname = "Posse" },
                    new Person() { Id = 4, Firstname = "Benoite", Lastname = "Gobel" },
                    new Person() { Id = 5, Firstname = "Charlot", Lastname = "Fullicks" },
                    new Person() { Id = 6, Firstname = "Vinson", Lastname = "Turbat" },
                    new Person() { Id = 7, Firstname = "Lenore", Lastname = "Malam" },
                    new Person() { Id = 8, Firstname = "Emanuele", Lastname = "Kolakovic" }
                });
        Roles.AddRange(new List<Role>()
            {
                    new Role() { Id = 1, Rolename = "Programmer Frontend" },
                    new Role() { Id = 1, Rolename = "Programmer Backend" },
                    new Role() { Id = 2, Rolename = "UX Designer" },
                    new Role() { Id = 3, Rolename = "DBA Developer" }
                });
    }

    private async Task<IEnumerable<Person>> GetPeopleLocal(string searchText)
    {
        return await Task.FromResult(People.Where(x => x.Firstname.ToLower().Contains(searchText.ToLower())).ToList());
    }

    private async Task<IEnumerable<Role>> GetRolesLocal(string searchText)
    {
        return await Task.FromResult(Roles.Where(x => x.Rolename.ToLower().Contains(searchText.ToLower())).ToList());
    }

    public void OnEmployeeDelete(Employee employee)
    {
        EmployeeList.Remove(employee);
    }

    public void OnEmployeeAdd()
    {
        EmployeeList.Add(new Employee());
    }

    private async Task CreateEmployeeList()
    {
        foreach (var employee in EmployeeList)
        {
            var resultPerson = employee.Person;
            var resultRole = employee.Role;
        }
    }
}

screen shoot of application

My problem is when I add a new row by clicking "Add Employee" and choose some value for name and role (e.g. Samara and Developer .NET) then all row gets same values. Furthermore when I click the "Create Employee List" button which calls the CreateEmployeeList method then EmployeeList have null values in all rows.

And when trying to delete a row the method OnEmployeeDelete removes the last row, regardless to which row I clicked.

The employee class

public class Employee
{
    public Employee() { }
    public Employee(Person person, Role role)
    {
        Person = person;
        Role = role;
    }

    public Person Person { get; set; }
    public Role Role { get; set; }
}

The role class

public class Role
{
    public Role() { }
    public Role(int id, string rolename)
    {
        Id = id;
        Rolename = rolename;
    }

    public int Id { get; set; }
    public string Rolename { get; set; }
}

Note I'm using the repo from Blazor Typeahead: https://github.com/Blazored/Typeahead I have just created a page Foreach.razor and added above code to it.

1 answer

  • answered 2022-05-04 10:43 Yong Shun

    From the attached code, @SelectedPerson and @SelectedRole are shared for each element in EmployeeList. That is why changing @SelectedPerson or @SelectedRole in a row will reflect in the other elements.

    You need a variable to hold the selected employee list.

    @foreach (var selectedEmployee in SelectedEmployeeList)
    {
        <div class="row">
            <div class="col-3">
                <BlazoredTypeahead SearchMethod="@GetPeopleLocal"
                               @bind-Value="@selectedEmployee.Person"
                               placeholder="Search by first name...">
                    <SelectedTemplate Context="person">
                        @person.Firstname
                    </SelectedTemplate>
                    <ResultTemplate Context="person">
                        @person.Firstname @person.Lastname
                    </ResultTemplate>
                </BlazoredTypeahead>
            </div>
            <div class="col-3">
                <BlazoredTypeahead SearchMethod="@GetRolesLocal"
                               @bind-Value="@selectedEmployee.Role"
                               placeholder="Search by role name...">
                    <SelectedTemplate Context="role">
                        @role.Rolename
                    </SelectedTemplate>
                    <ResultTemplate Context="role">
                        @role.Rolename
                    </ResultTemplate>
                </BlazoredTypeahead>
            </div>
            <div class="col-1">
                <a href="javascript:void(0)" class="btn btn-danger" @onclick="@(()=>OnEmployeeDelete(selectedEmployee))">X</a>
            </div>
        </div>
    }
    
    private List<Employee> SelectedEmployeeList = new List<Employee>();
    
    public void OnEmployeeDelete(Employee employee)
    {
        SelectedEmployeeList.Remove(employee);
    }
    
    public void OnEmployeeAdd()
    {
        SelectedEmployeeList.Add(new Employee());
    }
    
    private async Task CreateEmployeeList()
    {
        foreach (var employee in EmployeeList)
        {
            SelectedEmployeeList.Add(new Employee { Person = employee.Person, Role = employee.Role });
        }
    }
    

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum