DavidWaldo
DavidWaldo

Reputation: 735

Blazor, virtualized checkbox list

I'm trying to implement new "Virtualize" feature, by creating an scrollable list of checkboxes, where user can search and select multiple items.

Here is my razor code:

@if (this.AllowSearch)
{
    <InputTextLined Label="@string.Empty" @bind-Value="@SearchString"/>
}

<Virtualize Items="@displayedItems" Context="item" >
    <ItemContent>
        <label><input type="checkbox" @bind-value="item.Selected" />@item.DisplayName</label>
    </ItemContent>
</Virtualize>

</ul>

Heres my component code:

    [Parameter]
    public bool AllowSearch { get; set; } = false;

    [Parameter]
    public string DisplayPropertyName { get; set; }

    [Parameter]
    public ICollection<T> SourceList { get; set; } = null;

    [Parameter]
    public Func<T, string, bool> SearchFunc { get; set; }

    public string SearchString 
    { 
        get => _searchString;
        set 
        {
            if (value == _searchString)
                return;

            _searchString = value;
            Search();
        }
    }
    private string _searchString = string.Empty;

    protected ICollection<SelectableListItemModel<T>> items;
    protected ICollection<SelectableListItemModel<T>> displayedItems;

    protected override void OnInitialized()
    {
        if (SourceList != null)
        {
            items = SourceList.Select(i => new SelectableListItemModel<T>(i, DisplayPropertyName)).ToList();
            displayedItems = items.ToList();
        }
    }

    protected void Search()
    {
        if (string.IsNullOrWhiteSpace(SearchString) == false)
            displayedItems = items.Where(p => SearchFunc(p.Data, SearchString)).ToList();
        else
            displayedItems = items.ToList();
    }

The component renders all the items from sourceList by wraping them in SelectableListItemModel.

public class SelectableListItemModel<T> 
{
    public bool Selected { get; set; }
    
    public string DisplayName { get; set; }

    public T Data { get; private set; }

    public SelectableListItemModel(T data, string displayedPropertyName)
    {
        this.selected = false;
        this.Data = data;

        if (displayedPropertyName != string.Empty)
            this.DisplayName = typeof(T).GetProperty(displayedPropertyName).GetValue(data).ToString();
        else
            this.DisplayName = data.ToString();
    }
}

Now the main issue is with search implementation. But the problem is really hard to explain. Heres picture:

enter image description here

When item is selected and then performed a search, checkboxes are not rerendered, only labels.

Upvotes: 2

Views: 872

Answers (1)

nAviD
nAviD

Reputation: 3261

I think you should use InputCheckbox rather than html input element. The InputCheckBox implemented ValueChanged to notify the parents. And also use @item.Selected(with @ at the beginning) instead of item.Selected because item.selected is string! :

<EditForm>
<Virtualize Items="@displayedItems" Context="item" >
    <ItemContent>
        <label><InputCheckbox @bind-value="@item.Selected"></InputCheckbox>@item.DisplayName</label>
    </ItemContent>
</Virtualize>
</EditForm>

And

   protected aync Task Search()
        {
            if (string.IsNullOrWhiteSpace(SearchString) == false)
            {
                displayedItems = items.Where(p => await SearchFunc(p.Data,SearchString)).ToList();
                StateHasChanged();
            }
            else
                displayedItems = items.ToList();
        }

Upvotes: 1

Related Questions