React Grid 検索フィルター

    React Grid の Ignite UI for React 検索フィルター機能を使用すると、データのコレクション内の値を検索するプロセスが可能になります。この機能のセットアップが簡単になり、検索入力ボックス、ボタン、キーボード ナビゲーション、その他の便利な機能を使用して実装できるため、ユーザー エクスペリエンスがさらに向上します。ブラウザーにはネイティブなコンテンツ検索機能がありますが、ほとんどの場合で IgrGrid は表示範囲外の行列を仮想化します。そのため、ネイティブ ブラウザー検索は DOM の一部でないため仮想化セルでデータを検索できません。IgrGrid では、React Material テーブル ベースのグリッドの拡張により、検索 API を使用した仮想コンテンツの検索が可能です。

    React 検索の例

    次の例は、すべての列と行を検索できる検索入力ボックスと、各列の特定のフィルタリング オプションを備えた IgrGrid を表しています。

    React 検索の使用

    Grid のセットアップ

    グリッドを作成してからデータをバインドします。コンポーネントにカスタム スタイルも追加しました。

    .gridSize {
        --ig-size: var(--ig-size-small);
    }
    
    <IgrGrid ref={gridRef} className="gridSize" autoGenerate="false" allowFiltering="true" data={data}>
        <IgrColumn field="IndustrySector" dataType="string" sortable="true"></IgrColumn>        
        <IgrColumn field="IndustryGroup" dataType="string" sortable="true"></IgrColumn>        
        <IgrColumn field="SectorType" dataType="string" sortable="true"></IgrColumn>        
        <IgrColumn field="KRD" dataType="number" sortable="true"></IgrColumn>        
        <IgrColumn field="MarketNotion" dataType="number" sortable="true"></IgrColumn>  
    </IgrGrid>
    

    では、IgrGrid の検索 API の準備をしましょう。検索したテキストの保存、また大文字小文字の区別や完全一致 (またはそのいずれか) に使用するプロパティを作成できます。

    const gridRef = useRef<IgrGrid>(null);
    const searchIconRef = useRef<IgrIconButton>(null)
    const clearIconRef = useRef<IgrIconButton>(null);
    const iconButtonPrevRef = useRef<IgrIconButton>(null);
    const caseSensitiveChipRef = useRef<IgrChip>(null);
    const exactMatchChipRef = useRef<IgrChip>(null);
    const iconButtonNextRef = useRef<IgrIconButton>(null);
    const [searchText, setSearchText] = useState('')
    

    React 検索ボックス入力

    検索入力を作成します。searchText を新しく作成したinput要素の value プロパティにバインドし、inputOccured イベントをサブスクライブすることで、ユーザーによるすべての searchText の変更を検出できます。これにより、IgrGridfindNext メソッドと findPrev メソッドを使用して、searchText が出現するすべての箇所をハイライト表示し、(呼び出したメソッドに応じて) 次 / 前の箇所にスクロールできるようになります。

    findNextfindPrev メソッドの両方に 3 つの引数があります。

    • Text: string (検索テキスト)
    • (オプション) CaseSensitive: boolean (検索で完全一致するかどうか、デフォルト値は false)。
    • (オプション) ExactMatch: boolean (検索で完全一致するかどうか、デフォルト値は false)。

    完全一致で検索した場合、検索 API は SearchText と完全一致 (大文字小文字の区別を含む) するセル値のみ結果としてハイライト表示します。たとえば、文字列 'software' と 'Software' は大文字小文字を区別しない場合は完全一致となります。

    上記のメソッドは number 値を返します (IgrGrid で指定した文字列が含まれる回数)。

    function handleOnSearchChange(input: IgrInput, event: IgrComponentValueChangedEventArgs) {
        setSearchText(event.detail);
        gridRef.current.findNext(event.detail, caseSensitiveChipRef.current.selected, exactMatchChipRef.current.selected);
    }
    
    function nextSearch() {
        gridRef.current.findNext(searchText, caseSensitiveChipRef.current.selected, exactMatchChipRef.current.selected);
    }
    
    
    <IgrInput name="searchBox" value={searchText} inputOcurred={handleOnSearchChange}>
    </IgrInput>
    

    検索ボタンの追加

    ボタンの各クリック イベント ハンドラー内で findNextfindPrev メソッドを呼び出して検索や検索結果をナビゲーションするためのボタンを作成します。

    function prevSearch() {
        gridRef.current.findPrev(searchText, caseSensitiveChipRef.current.selected, exactMatchChipRef.current.selected);
    }
    
    function nextSearch() {
        gridRef.current.findNext(searchText, caseSensitiveChipRef.current.selected, exactMatchChipRef.current.selected);
    }
    
    <IgrIconButton key="prevIconButton" ref={iconButtonPrevRef} variant="flat" name="prev" collection="material" clicked={prevSearch}>
    </IgrIconButton>
    <IgrIconButton key="nextIconButton" ref={iconButtonNextRef} variant="flat" name="next" collection="material" clicked={nextSearch}>
    </IgrIconButton>
    

    キーボード検索の追加

    ユーザーは矢印キーと Enter キーで結果を移動できます。PreventDefault メソッドのデフォルト キャレットの移動を防止する検索入力の keydown イベントを処理し、ユーザーが押したキーに基づいて findNext/findPrev メソッドを呼び出します。

    function searchKeyDown(e: KeyboardEvent<HTMLElement>) {
        if (e.key === 'Enter') {
            e.preventDefault();
            gridRef.current.findNext(searchText, caseSensitiveChipRef.current.selected, exactMatchChipRef.current.selected);
        } else if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') {
            e.preventDefault();
            gridRef.current.findPrev(searchText, caseSensitiveChipRef.current.selected, exactMatchChipRef.current.selected);
        }
    }
    
     <div onKeyDown={searchKeyDown}>
        <IgrInput name="searchBox" value={searchText} inputOcurred={handleOnSearchChange}></IgrInput>
    </div>
    

    大文字と小文字の区別と完全一致

    次に完全一致の検索で大文字と小文字を区別するかどうかをユーザーが選択できるようにします。この目的のために、IgrChip を使用してその参照を取得し、selected プロパティを使用できます。

    const caseSensitiveChipRef = useRef<IgrChip>(null);
    const exactMatchChipRef = useRef<IgrChip>(null);
    
    function updateSearch() {
        gridRef.current.findNext("searchValue", caseSensitiveChipRef.current.selected, exactMatchChipRef.current.selected);
    }
    
    <IgrChip ref={caseSensitiveChipRef} key="caseSensitiveChip" selectable="true">
        <span key="caseSensitive">Case Sensitive</span>
    </IgrChip>
    <IgrChip ref={exactMatchChipRef} key="exactMatchChip" selectable="true">
        <span key="exactMatch">Exact Match</span>
    </IgrChip>
    

    保持

    IgrGrid のフィルターやソート、レコードの追加や削除をする場合を想定します。そのような処理の後、現在の検索が自動的に更新されて SearchText に一致するテキストが保持されます。更に検索がページングで動作し、IgrGridPerPage プロパティの変更時もハイライト表示が保持されます。

    アイコンの追加

    その他のコンポーネントを使用するためにユーザー インターフェイスを作成し、検索バー全体のデザインを向上します。検索入力の左側に検索または削除アイコン、検索オプションのチップ、右側にはマテリアル デザイン アイコンと Ripple スタイルのボタンを組み合わせたナビゲーションを表示できます。入力グループ内のコンポーネントをラップしてより洗練されたデザインにすることができます。

    import { IgrGridModule } from "igniteui-react-grids";
    import { IgrChipModule } from "igniteui-react";
    
    const mods: any[] = [IgrGridModule, IgrChipModule];
    mods.forEach((m) => m.register());
    

    テンプレートを新しいコンポーネントで更新します。

    const prevIconText =
      "<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 nextIconText =
      "<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 clearIconText =
      "<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>";
      const searchIconText =
      "<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>";
    
    useEffect(() => {
         if (searchIconRef?.current) {
          searchIconRef.current.registerIconFromText("search", searchIconText, "material");
          searchIconRef.current.registerIconFromText("clear", clearIconText, "material");
        }
        if (iconButtonPrevRef?.current) {
            iconButtonPrevRef.current.registerIconFromText("prev", prevIconText, "material");
        }
        if (iconButtonNextRef?.current) {
            iconButtonNextRef.current.registerIconFromText("next", nextIconText, "material");
        }
    }, []);
    
    <IgrInput name="searchBox" value={searchText} inputOcurred={handleOnSearchChange}>
        <div slot="prefix" key="prefix">
            {searchText.length === 0 ? (
                <IgrIconButton
                  key="searchIcon"
                  ref={searchIconRef} 
                  variant="flat"
                  name="search" 
                  collection="material"
                ></IgrIconButton>
                ) : (
                <IgrIconButton
                  key="clearIcon"
                  ref={clearIconRef}
                  variant="flat"
                  name="clear"
                  collection="material"
                  clicked={clearSearch}
                ></IgrIconButton>
            )}
        </div>
        <div slot="suffix" key="chipSuffix">
            <IgrChip ref={caseSensitiveChipRef} key="caseSensitiveChip" selectable="true">
            <span key="caseSensitive">Case Sensitive</span>
            </IgrChip>
            <IgrChip ref={exactMatchChipRef} key="exactMatchChip" selectable="true">
            <span key="exactMatch">Exact Match</span>
            </IgrChip>
        </div>
        <div slot="suffix" key="buttonsSuffix">
            <IgrIconButton key="prevIconButton" ref={iconButtonPrevRef} variant="flat" name="prev" collection="material" clicked={prevSearch}>
            </IgrIconButton>
            <IgrIconButton key="nextIconButton" ref={iconButtonNextRef} variant="flat" name="next" collection="material" clicked={nextSearch}>
            </IgrIconButton>
        </div>
    </IgrInput>
    

    右側の入力グループに以下の目的で別のコンテナーを作成します。

    • 以下は CaseSensitiveExactMatch を切り替えるチップを表示する方法です。プロパティに基づいて色が変わる 2 つのチップでチェックボックスを 置き換えます。チップをクリックすると、どちらのチップがクリックされたかによって各ハンドラーを呼び出します。
    <div slot="suffix" key="chipSuffix">
        <IgrChip ref={caseSensitiveChipRef} key="caseSensitiveChip" selectable="true" select={handleCaseSensitiveChange}>
            <span key="caseSensitive">Case Sensitive</span>
        </IgrChip>
        <IgrChip ref={exactMatchChipRef} key="exactMatchChip" selectable="true" select={handleExactMatchChange}>
            <span key="exactMatch">Exact Match</span>
        </IgrChip>
    </div>
    
    function handleCaseSensitiveChange(chip: IgrChip, event: IgrComponentBoolValueChangedEventArgs) {
      gridRef.current.findNext(searchText, event.detail, exactMatchChipRef.current.selected);
    }
    function handleExactMatchChange(chip: IgrChip, event: IgrComponentBoolValueChangedEventArgs) {
      gridRef.current.findNext(searchText, caseSensitiveChipRef.current.selected, event.detail);
    }
    
    • 検索ナビゲーション ボタンは、マテリアルアイコンを使用して入力を Ripple スタイルボタンにします。click イベントのハンドラーはそのままで findNext/findPrev メソッドを呼び出します。
    function prevSearch() {
        gridRef.current.findPrev(searchText, caseSensitiveChipRef.current.selected, exactMatchChipRef.current.selected);
    }
    
    function nextSearch() {
        gridRef.current.findNext(searchText, caseSensitiveChipRef.current.selected, exactMatchChipRef.current.selected);
    }
    
    <div slot="suffix" key="buttonsSuffix">
        <IgrIconButton key="prevIconButton" ref={iconButtonPrevRef} variant="flat" name="prev" collection="material" clicked={prevSearch}>
        </IgrIconButton>
        <IgrIconButton key="nextIconButton" ref={iconButtonNextRef} variant="flat" name="next" collection="material" clicked={nextSearch}>
        </IgrIconButton>
    </div>
    

    既知の問題と制限

    制限 説明
    テンプレートを使用したセル内の検索 検索機能のハイライト表示が、デフォルトのセルテンプレートに対してのみ機能する問題。カスタム セル テンプレートを含む列がある場合、ハイライト表示が機能しないため、列フォーマッタなどの代替アプローチを使用するか、searchable (検索可能な) プロパティを false に設定します。
    リモート仮想化 リモート仮想化の使用時に検索が正しく動作しません。
    セル テキストが切れる問題 セル内のテキストが長すぎるために検索テキストが省略記号によって切れている場合も、セルまでスクロールして一致カウントに含まれますが、ハイライト表示はされません。

    API リファレンス

    このトピックでは、IgrGrid にカスタム検索バーを実装し、更に検索結果を移動する際の機能を追加しました。アイコン、チップ、入力などその他の Ignite UI for React も使用しています。以下は検索 API です。

    IgrGrid メソッド:

    IgrColumn プロパティ:

    その他のコンポーネント (またはそのいずれか) で使用した API:

    その他のリソース

    コミュニティに参加して新しいアイデアをご提案ください。