2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

インクリメンタルサーチでサーバー側のAPIを書くのがめんどくさいので何とかした話

Posted at

注意!!

全てのシーンでのインクリメンタルサーチに対応できません。
数が少なく、更新頻度がかなり少ないorないレコードをインクリメンタルサーチする場合のみ適用できます。

何を言ってるの?

フロント検索UIで文字をタイピングした段階で検索した文字列にヒットしたDBにあるレコードを探す機能を作成した際のTipsです。

たとえば、100レコードほどしかなく、本人しか追加、削除しないなどの性質をもったテーブルです。
最初のレンダリング時に、DOMに持っておいて、DOM上で検索できるようにすれば、サーバー側に通信なく、データを表示非表示できると思ったので、実践してみました。
普段使わないあまり使わないであろうXpathでの実装です。

コードはこんな感じ

CSS

display-none {
   display: none;
}

TypeScript

    // 検索フォーム
    this.search = <HTMLInputElement>>document.querySelector('#search');
    // 検索対象のDOM
    this.searchTargets = <NodeListOf<HTMLElement>>document.querySelectorAll('.target');

    // イベントリスナー
    this.search.addEventListener("keyup", this.searchKeyUpHandler());

    /**
     * 検索窓に入力された文字列で検索
     *
     * @param e HTMLElementEvent<HTMLInputElement>
     */
    private searchCallTrackingWordKeyUpHandler = (e: HTMLElementEvent<HTMLInputElement>) => {
        e.preventDefault();

        // 文字が入力されてなければ、全ての行を表示し処理終了
        if (e.currentTarget.value.length == 0) {
            for (let i: number = 0, len: number = this.searchTargets.length; i < len; i++) {
                this.searchTargets[i].classList.remove("display-none");
            }
            return;
        }

        // 初期化(全て非表示)
        for (let i: number = 0, len: number = this.searchTargets.length; i < len; i++) {
            this.searchTargets[i].classList.add("display-none");
        }

        // xPathに変換し、検索窓に入力された文字列でテキストノードを取得
        const xPathTextNodeResult: XPathResult = document.evaluate(
            `//div[contains(@class, 'target')]/div/text()[contains(., "${e.currentTarget.value}")]`,
            document,
            null,
            XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
            null
        );

        // テキストノードの数
        let snapshotLength: number = xPathTextNodeResult.snapshotLength;

        // テキストノードの親要素を取得し、表示する
        while (snapshotLength--) {
            const searchTarget = xPathTextNodeResult.snapshotItem(snapshotLength)!.parentElement!.closest('.
target')!;
            searchTarget.classList.remove('display-none');
        }
    }

メリット・デメリット

  • メリット
    フロント・サーバー側に記述が少なくなるはず。
    DOMそのものを書き換えないので、検索した結果にイベントリスナーなどする場合は一度で済む(API通信だと、今描画してる検索結果のDOMを削除して、再度、createElementし、イベントリスナーする流れだと思われるが、この手法だと表示非表示なので、SSR時などに一度だけイベントリスナーすれば良い)

  • デメリット
    裏で、更新された場合、リアルタイムで最新の情報が得られない。あくまでSSR時の情報だけ。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?