【JavaScript】キーワード検索でリアルタイムにコンテンツ表示させる

# 概要

DBに登録されているスケジュールを全件取得し一覧表示。一覧表示されているスケジュールに対し、`<input>`で入力したキーワードでスケジュールのタイトル、作成者に該当する スケジュールを表示し、該当しないスケジュールは非表示にする。
また、文字が入力されるたびに検索処理が走り、部分一致検索にてキーワードに該当するスケジュールを表示する。

# 完成イメージ
![画面収録-2022-06-10-13.05.40.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638572/611dfaff-67ea-92cd-9e48-ab976c2a57b1.gif)


# コード

```html:index.html
//検索バー
<p>
	<input type="text" id="serch_schedule" placeholder="キーワードで検索">
</p>

//検索対象のスケジュール
<ul id="display_schedule_area">
	<li class="schedule" data-title="スケジュール１" data-author="田中さん">
		<a href="#">
			<dl>
				<dt>6/6 19:40 〜 6/6 19:41<span>田中さん</span></dt>
				<dd>スケジュール１</dd>
			</dl>
		</a>
	</li>
	<li class="schedule" data-title="スケジュール2" data-author="川島さん">
		<a href="#">
			<dl>
				<dt>6/6 19:40 〜 6/6 19:41<span>川島さん</span></dt>
				<dd>スケジュール2</dd>
			</dl>
		</a>
	</li>
	<li class="schedule" data-title="スケジュール３" data-author="西村さん">
		<a href="#">
			<dl>
				<dt>6/6 19:40 〜 6/6 19:41<span>田中さん</span></dt>
				<dd>スケジュール３</dd>
			</dl>
		</a>
	</li>
  //検索結果が0件の時に表示
	<li class="no_schedule" data-title="" data-author="">検索したスケジュールは見つかりませんでした</li>
</ul>
```

```jsx:main.js

document.getElementById("serch_schedule").addEventListener("input", searchSchedule);

const searchSchedule = (e) => {
	const keyword = e.target.value;
	const $schedules = document.querySelectorAll("#display_schedule_area > li");
	const $no_schedule = document.querySelector(".no_schedule");
	$no_schedule.style.display = "none";
	if (keyword) {
		$schedules.forEach(e => e.style.display = "none");
		const filter = Array.from($schedules).filter(e => {
			const schedule_title = e.dataset.title;
			const schedule_author = e.dataset.author;
			if (schedule_title.indexOf(keyword.toLowerCase()) !== -1 ||
				schedule_title.indexOf(keyword.toUpperCase()) !== -1 ||
				schedule_author.indexOf(keyword.toLowerCase()) !== -1 ||
				schedule_author.indexOf(keyword.toUpperCase()) !== -1) {
				return e;
			}
		});
		filter.length === 0 ? $no_schedule.style.display = "block" : filter.forEach(e => e.style.display = "block");
	} else {
		$schedules.forEach(e => e.style.display = "block");
		$no_schedule.style.display = "none";
	}
}
```

# 解説

```jsx:main.js
document.getElementById("serch_schedule").addEventListener("input", searchSchedule);
```

- 検索バーに文字が1文字入力されるたびに `searchSchedule` メソッドが実行される。

```jsx:main.js
const keyword = e.target.value;
const $schedules = document.querySelectorAll("#display_schedule_area > li");
const $no_schedule = document.querySelector(".no_schedule");
$no_schedule.style.display = "none";
```

- 入力したキーワード、検索対象の `<li>` 要素、検索結果が0件だった場合に表示する `<li>` 要素を変数に格納。
- `$no_schedule` は非表示にしておく。
- アロー関数において入力されたキーワード（ `<input>`タグの `value`）は `this` の参照先が**windowオブジェクトを参照**するため `this.value` では取得できない

> [https://codelikes.com/javascript-arrow-function/](https://codelikes.com/javascript-arrow-function/)

```jsx:main.js
$schedules.forEach(e => e.style.display = "none");
```

- キーワードが入力されれば一旦検索対象の `<li>` 要素は非表示にする（初期化）

```jsx:main.js
const filter = Array.from($schedules).filter(e => {
			const schedule_title = e.dataset.title;
			const schedule_author = e.dataset.author;
			if (schedule_title.indexOf(keyword.toLowerCase()) !== -1 ||
				schedule_title.indexOf(keyword.toUpperCase()) !== -1 ||
				schedule_author.indexOf(keyword.toLowerCase()) !== -1 ||
				schedule_author.indexOf(keyword.toUpperCase()) !== -1) {
				return e;
});
```

- NodeListの `$schedules`に対して `filter` メソッドを実行するとエラーになるので、`Array.from($schedules)` で配列に変換後、`filter` メソッドを実行。
- `indexOf` メソッドで条件に合致する `<li>` 要素を変数 `filter` に格納し、新たに配列を作成する。
- `toUpperCase` メソッドと `toLowerCase` メソッドで大文字、小文字どちらでもヒットするようになる。

> [Array.from()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/from)

```jsx:main.js
filter.length === 0 ? $no_schedule.style.display = "block" : filter.forEach(e => e.style.display = "block");
```

- 配列 `filter` が空でない場合は `forEach` メソッドで順番に表示する。
- 配列が空の場合は0件用の `<li>` 要素を表示する。

# 参考

- [【JavaScript】配列系メソッドあれこれ](https://qiita.com/shiho97797/items/a3ed8596f9f98c064e7e)
- [HTML CollectionとNodeListの違い【JavaScript】](https://code-r-dev.com/html-collection-vs-nodelist/)