【DAY25】投稿画面における文字数の表示(2)

この記事は以下の記事の続きとなります。
[【DAY24】投稿画面における文字数の表示(1)](https://qiita.com/Nautilus1256/items/27ce3f27baa75d70b01e)

## 関数を使い回したい
前回は、質問タイトルの入力に対してJSを記述して機能を実装しました。しかし、同じページの質問詳細の入力に対しても同じ機能を付けたいです。今の状態では関数の使い回しができないので、ビューとJSの記述を以下のように変更します。
```html
<input type="text" name="question[title]" placeholder="タイトル" value="{{ old("question.title") }}" class="w-full rounded-2xl p-4 text-xl count-text" data-count-target="question-title-count"/>
<p><span id="question-title-count">0</span>/50文字</p>
```
↑inputタグのクラスにcount-textを追加し、idではなくdata属性を記述しました。

```count.js
const characterCount = (inputElement) => {
    const countTargetId = inputElement.dataset.countTarget;
    const countTarget = document.querySelector(`#${countTargetId}`);
    
    inputElement.addEventListener('keyup', () => {
        const length = inputElement.value.length;
        countTarget.textContent = length;
        
        if (length > 50) {
            countTarget.classList.add('text-red-500');
        } else {
            countTarget.classList.remove('text-red-500');
        }
    });
}

document.querySelectorAll('.count-text').forEach(inputElement => {
    characterCount(inputElement);
});
```
処理をcharacterCount関数に記述し、count-textクラスを持つ要素に対して関数の処理を行うようにしました。
inputタグのdata-count-targetの値と、数を表示するspanタグのidの値を一致させているため、spanタグの要素を取得して数の表示を変えることができます。

これで、他のテキスト入力欄についてもcount-textクラスとdata属性をつけることで同じ関数を使用できるようになりました。

## 文字数制限の指定
質問タイトルは50字以内でしたが、質問詳細は400字以内に設定しています。今のままでは50字を超えた時点で文字が赤に変わってしまいます。そこで、文字数制限も取得して関数に組み込みます。
```html
<!--data-maxlengthを追加-->
<input type="text" name="question[title]" placeholder="タイトル" value="{{ old("question.title") }}" class="w-full rounded-2xl p-4 text-xl count-text" data-maxlength="50" data-count-target="question-title-count"/>
<p><span id="question-title-count">0</span>/50文字</p>
```
``` count.js
const characterCount = (inputElement) => {
    const maxLength = inputElement.dataset.maxlength; //追加
    const countTargetId = inputElement.dataset.countTarget;
    const countTarget = document.querySelector(`#${countTargetId}`);
    
    inputElement.addEventListener('keyup', () => {
        const length = inputElement.value.length;
        countTarget.textContent = length;
        
        if (length > maxLength /*変更*/) {
            countTarget.classList.add('text-red-500');
        } else {
            countTarget.classList.remove('text-red-500');
        }
    });
}

document.querySelectorAll('.count-text').forEach(inputElement => {
    characterCount(inputElement);
});
```
これで、文字数制限が異なる入力フォームに対してもmaxlengthを指定することで対応できるようになりました。

## idを使用しない指定
質問投稿画面とほとんど内容が同じ、質問編集画面も作っています。このように似たページが複数あると、spanタグのidを一意に決めるのが面倒です。そこで、idを使わず要素を特定できるようにしてみます。
```html
<!--data-count-targetを削除-->
<input type="text" name="question[title]" placeholder="タイトル" value="{{ old("question.title") }}" class="w-full rounded-2xl p-4 text-xl count-text" data-maxlength="50"/>
<!--idを削除、クラス名にcount-displayを追加-->
<p><span class="count-display">0</span>/50文字</p>
```

```count.js
const characterCount = (inputElement) => {
    const maxLength = inputElement.dataset.maxlength;
    // 変更
    const countTarget = inputElement.nextElementSibling.querySelector('.count-display');
    
    inputElement.addEventListener('keyup', () => {
        const length = inputElement.value.length;
        countTarget.textContent = length;
        
        if (length > maxLength) {
            countTarget.classList.add('text-red-500');
        } else {
            countTarget.classList.remove('text-red-500');
        }
    });
}

document.querySelectorAll('.count-text').forEach(inputElement => {
    characterCount(inputElement);
});
```

nextElementSiblingを使って、次にあるcount-displayクラスを持つ要素にアクセスするようにします。
これで、一意にidを指定する必要がなくなりました。
しかし、nextElementSiblingを使っているため、htmlの記述によっては反映されないので注意が必要そうです。
## 機能実装後の質問投稿画面
![スクリーンショット 2024-10-02 14.36.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818045/7a60080b-b66d-b95f-9f4a-7e7e0f53d7f7.png)

質問タイトルは50字を超えて数字が赤色になっていますが、質問内容詳細は400字以内なので黒色のままです。