Filtro de pesquisa de grade Blazor

    O recurso Ignite UI for Blazor Search Filter no Blazor Grid permite o processo de encontrar valores na coleta de dados. Facilitamos a configuração dessa funcionalidade e ela pode ser implementada com uma caixa de entrada de pesquisa, botões, navegação por teclado e outros recursos úteis para uma experiência do usuário ainda melhor. Embora os navegadores forneçam nativamente a funcionalidade de pesquisa de conteúdo, na maioria das vezes o IgbGrid virtualiza suas colunas e linhas que estão fora de exibição. Nesses casos, a pesquisa nativa do navegador não consegue pesquisar dados nas células virtualizadas, pois elas não fazem parte do DOM. Estendemos a grade baseada em tabela Blazor Material com uma API de pesquisa que permite pesquisar no conteúdo virtualizado do IgbGrid.

    Blazor Search Example

    O exemplo a seguir representa IgbGrid com uma caixa de entrada de pesquisa que permite pesquisar em todas as colunas e linhas, bem como opções de filtragem específicas para cada coluna.

    Blazor Search Usage

    Grid Setup

    Vamos começar criando nossa grade e vinculando-a aos nossos dados. Também adicionaremos alguns estilos personalizados para os componentes que usaremos!

    .gridSize {
        --ig-size: var(--ig-size-small);
    }
    
    <IgbGrid @ref=grid Class="gridSize" Width="100%" Height="480px" AllowFiltering=true AutoGenerate=false Data=marketData>
        <IgbColumn Field="IndustrySector" DataType="GridColumnDataType.String" Sortable=true></IgbColumn>
        <IgbColumn Field="IndustryGroup" DataType="GridColumnDataType.String" Sortable=true></IgbColumn>
        <IgbColumn Field="SectorType" DataType="GridColumnDataType.String" Sortable=true></IgbColumn>
        <IgbColumn Field="KRD" DataType="GridColumnDataType.Number" Sortable=true></IgbColumn>
        <IgbColumn Field="MarketNotion" DataType="GridColumnDataType.Number" Sortable=true></IgbColumn>
    </IgbGrid>
    
    @code {
        protected override void OnInitialized()
        {
            base.OnInitialized();
            this.marketData = MarketData.GetData();
        }
    }
    

    Ótimo, e agora vamos nos preparar para a API de busca do nosso IgbGrid! Podemos criar algumas propriedades, que podem ser usadas para armazenar o texto pesquisado atualmente e se a busca é sensível a maiúsculas e minúsculas e/ou por uma correspondência exata.

    public string searchText = "";
    public bool caseSensitive = false;
    public bool exactMatch = false;
    

    Blazor Search Box Input

    Agora vamos criar nossa entrada de pesquisa! Ao vincular nosso SearchText à propriedade Value para nossa entrada recém-criada e assinar o evento ValueChanging, podemos detectar cada modificação SearchText feita pelo usuário. Isso nos permitirá usar os métodos FindNext e FindPrev do IgbGrid para destacar todas as ocorrências do SearchText e rolar para a próxima/anterior (dependendo de qual método invocamos).

    Os métodos FindNext e FindPrev têm três argumentos:

    • Text: string (o texto que estamos procurando)
    • (opcional) CaseSensitive: boolean (a pesquisa deve diferenciar maiúsculas de minúsculas ou não, o valor padrão é false)
    • (opcional) ExactMatch: boolean (a busca deve ser por uma correspondência exata ou não, o valor padrão é false)

    Ao pesquisar por uma correspondência exata, a API de pesquisa destacará como resultados apenas os valores de células que correspondem inteiramente ao SearchText, levando em conta também a diferenciação entre maiúsculas e minúsculas. Por exemplo, as strings 'software' e 'Software' são uma correspondência exata, desconsiderando a diferenciação entre maiúsculas e minúsculas.

    Os métodos acima retornam um valor numérico (o número de vezes que o IgbGrid contém a string fornecida).

    <IgbInput ValueChanging="valueChanging" Value="@searchText" />
    

    Add Search Buttons

    Para pesquisar e navegar livremente entre nossos resultados de pesquisa, vamos criar alguns botões invocando os métodos FindNext e FindPrev dentro dos respectivos manipuladores de eventos de clique dos botões.

    <IgbIconButton Variant="IconButtonVariant.Flat" @onclick="PrevSearch">
        <IgbIcon IconName="prev" Collection="material"/>
    </IgbIconButton>
    <IgbIconButton Variant="IconButtonVariant.Flat" @onclick="NextSearch">
        <IgbIcon IconName="next" Collection="material" />
    </IgbIconButton>
    
    @code {
        private IgbGrid grid;
        public void PrevSearch()
        {
            this.grid.FindPrevAsync(this.searchText, this.caseSensitive, this.exactMatch);
        }
    
        public void NextSearch()
        {
            this.grid.FindNextAsync(this.searchText, this.caseSensitive, this.exactMatch);
        }
    }
    

    Também podemos permitir que os usuários naveguem pelos resultados usando as teclas de seta do teclado e a tecla Enter. Para conseguir isso, podemos manipular o evento keydown da nossa entrada de pesquisa impedindo o movimento de cursor padrão da entrada com o método PreventDefault e invocar os métodos FindNext / FindPrev dependendo de qual tecla o usuário pressionou.

    Também podemos permitir que os usuários naveguem pelos resultados usando a tecla Enter do teclado. Para conseguir isso, podemos manipular o evento keydown da nossa pesquisa e invocar os métodos FindNext / FindPrev dependendo se o usuário pressionou Shift também ou não.

    <IgbInput ValueChanging="valueChanging" Value="@searchText" @onkeydown="OnSearchKeyDown"/>
    
    @code {
        private void OnSearchKeyDown(KeyboardEventArgs evt)
        {
            if (evt.Key == "Enter" && !evt.ShiftKey) {
                this.grid.FindNextAsync(this.searchText, this.caseSensitive, this.exactMatch);
            } else if (evt.Key == "Enter") {
                this.grid.FindPrevAsync(this.searchText, this.caseSensitive, this.exactMatch);
            }
        }
    }
    

    Case Sensitive and Exact Match

    Agora vamos permitir que o usuário escolha se a busca deve ser sensível a maiúsculas e minúsculas e/ou por uma correspondência exata. Para esse propósito, podemos usar Chips selecionáveis simples e vincular ao evento SelectedChanged para determinar quando o usuário interage com eles.

    <IgbChip Selectable=true SelectedChanged="UpdateCase">
        Case Sensitive
    </IgbChip>
    <IgbChip  Selectable=true SelectedChanged="UpdateExactSearch">
        Exact Match
    </IgbChip>
    
    @code {
        public void UpdateCase(bool selected) {
            this.caseSensitive = selected;
            this.grid.FindNextAsync(this.searchText, this.caseSensitive, this.exactMatch);
        }
    
        public void UpdateExactSearch(bool selected) {
            this.exactMatch = selected;
            this.grid.FindNextAsync(this.searchText, this.caseSensitive, this.exactMatch);
        }
    }
    

    Persistence

    E se quiséssemos filtrar e classificar nossos IgbGrid ou mesmo adicionar e remover registros? Após tais operações, os destaques da nossa pesquisa atual são atualizados automaticamente e persistem sobre qualquer texto que corresponda ao SearchText! Além disso, a busca funcionará com paginação e persistirá os destaques por meio de alterações do IgbGrid 's PerPage propriedade.

    Adding icons

    Ao usar alguns dos nossos outros componentes, podemos criar uma interface de usuário enriquecida e melhorar o design geral de toda a nossa barra de pesquisa! Podemos ter um belo ícone de pesquisa ou exclusão à esquerda da entrada de pesquisa, alguns chips para nossas opções de pesquisa e alguns ícones de material design combinados com belos botões em estilo ripple para nossa navegação à direita. Podemos envolver esses componentes dentro de um grupo de entrada para um design mais refinado.

    Para fazer isso, vamos pegar os módulos IgbInput, IgbIcon, IgbIconButton e IgbChip.

    // eg. Program.cs register the following:
    builder.Services.AddIgniteUIBlazor(
        typeof(IgbGridModule),
        typeof(IgbInputModule),
        typeof(IgbIconButtonModule),
        typeof(IgbIconModule)
    );
    
    @code {
        private IgbIcon searchIconRef { get; set; }
        const string searchIcon = "<svg width='24' height='24' viewBox='0 0 24 24'><path d='M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z' /></svg>";
        const string prevIcon = "<svg width='24' height='24' viewBox='0 0 24 24'><path d='M15.41 7.41 14 6l-6 6 6 6 1.41-1.41L10.83 12z'></path></svg>";
        const string nextIcon = "<svg width='24' height='24' viewBox='0 0 24 24'><path d='M10 6 8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z'></path></svg>";
        const string clearIcon = "<svg width='24' height='24' viewBox='0 0 24 24' title='Clear'><path d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'></path></svg>";
        
        protected override void OnAfterRender(bool firstRender)
        {
            if (this.searchIconRef != null && firstRender)
            {
                this.searchIconRef.EnsureReady().ContinueWith(new Action<Task>((e) =>
                {
                    this.searchIconRef.RegisterIconFromTextAsync("search", searchIcon, "material");
                    this.searchIconRef.RegisterIconFromTextAsync("prev", prevIcon, "material");
                    this.searchIconRef.RegisterIconFromTextAsync("next", nextIcon, "material");
                    this.searchIconRef.RegisterIconFromTextAsync("clear", clearIcon, "material");
                }));
            }
        }
    }
    

    Por fim, vamos atualizar nosso modelo com os novos componentes!

    Vamos envolver todos os nossos componentes dentro de um IgbInput. À esquerda, alternaremos entre um ícone de pesquisa e um ícone de exclusão/limpeza (dependendo se a entrada de pesquisa está vazia ou não). No centro, posicionaremos a própria entrada. Além disso, sempre que o ícone de exclusão for clicado, atualizaremos nosso SearchText e invocaremos o método ClearSearch do IgbGrid para limpar os destaques.

    <IgbInput ValueChanging="OnValueChanging" Value="@searchText" @onkeydown="OnSearchKeyDown">
        @if (searchText.Length == 0)
        {
            <IgbIcon @ref="searchIconRef" slot="prefix" IconName="search" Collection="material"/>
        }
        @if (searchText.Length > 0)
        {
            <IgbIcon slot="prefix" IconName="clear" Collection="material" @onclick="ClearSearch"/>
        }
    
        <div class="chips" slot="suffix">
            <IgbChip Selectable=true SelectedChanged="UpdateCase">
                Case Sensitive
            </IgbChip>
            <IgbChip  Selectable=true SelectedChanged="UpdateExactSearch">
                Exact Match
            </IgbChip>
        </div>
        <div class="searchButtons" slot="suffix">
            <IgbIconButton Variant="IconButtonVariant.Flat" @onclick="PrevSearch">
                <IgbIcon IconName="prev" Collection="material"/>
            </IgbIconButton>
            <IgbIconButton Variant="IconButtonVariant.Flat" @onclick="NextSearch">
                <IgbIcon IconName="next" Collection="material" />
            </IgbIconButton>
        </div>
    </IgbInput>
    
    @code {
    
        public void clearSearch()
        {
            this.searchText = "";
            this.grid.ClearSearchAsync();
        }
    }
    

    À direita, em nosso grupo de entrada, vamos criar três contêineres separados com as seguintes finalidades:

    • Para exibir alguns chips que alternam as propriedades CaseSensitive e ExactMatch. Substituímos as caixas de seleção por dois chips estilosos que mudam de cor com base nessas propriedades. Sempre que um chip é clicado, invocamos seu respectivo manipulador.
        <div class="chips" slot="suffix">
            <IgbChip Selectable=true SelectedChanged="UpdateCase">
                Case Sensitive
            </IgbChip>
            <IgbChip  Selectable=true SelectedChanged="UpdateExactSearch">
                Exact Match
            </IgbChip>
        </div>
    
    @code {
        public void UpdateCase(bool selected) {
            this.caseSensitive = selected;
            this.grid.FindNextAsync(this.searchText, this.caseSensitive, this.exactMatch);
        }
    
        public void UpdateExactSearch(bool selected) {
            this.exactMatch = selected;
            this.grid.FindNextAsync(this.searchText, this.caseSensitive, this.exactMatch);
        }
    }
    
    • Para os botões de navegação de pesquisa, transformamos nossas entradas em botões estilo ripple com ícones de material. Os manipuladores para os eventos de clique permanecem os mesmos - invocando os métodos FindNext / FindPrev.
    <div class="searchButtons" slot="suffix">
        <IgbIconButton Variant="IconButtonVariant.Flat" @onclick="PrevSearch">
            <IgbIcon IconName="prev" Collection="material"/>
        </IgbIconButton>
        <IgbIconButton Variant="IconButtonVariant.Flat" @onclick="NextSearch">
            <IgbIcon IconName="next" Collection="material" />
        </IgbIconButton>
    </div>
    @code {
        public void PrevSearch()
        {
            this.grid.FindPrevAsync(this.searchText, this.caseSensitive, this.exactMatch);
        }
    
        public void NextSearch()
        {
            this.grid.FindNextAsync(this.searchText, this.caseSensitive, this.exactMatch);
        }
    }
    

    Known Limitations

    Limitação Descrição
    Pesquisando em células com um modelo Os destaques da funcionalidade de pesquisa funcionam apenas para os modelos de célula padrão. Se você tiver uma coluna com modelo de célula personalizado, os destaques não funcionarão, então você deve usar abordagens alternativas, como um formatador de coluna, ou definir oSearchable propriedade na coluna como falsa.
    Virtualização Remota A pesquisa não funcionará corretamente ao usar virtualização remota
    Células com texto cortado Quando o texto na célula é muito grande para caber e o texto que estamos procurando é cortado pelas reticências, ainda rolaremos até a célula e a incluiremos na contagem de correspondências, mas nada será destacado

    API References

    Neste artigo, implementamos nossa própria barra de pesquisa para o IgbGrid com algumas funcionalidades adicionais quando se trata de navegar entre os resultados da pesquisa. Também usamos alguma Ignite UI for Blazor como ícones, chips e entradas. A API de pesquisa está listada abaixo.

    IgbGrid methods:

    IgbColumn properties:

    Componentes adicionais com APIs relativas que foram usadas:

    Additional Resources

    Nossa comunidade é ativa e sempre acolhedora para novas ideias.