0
0

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

Posted at

この記事は以下の記事の続きとなります。
【DAY24】投稿画面における文字数の表示(1)

関数を使い回したい

前回は、質問タイトルの入力に対してJSを記述して機能を実装しました。しかし、同じページの質問詳細の入力に対しても同じ機能を付けたいです。今の状態では関数の使い回しができないので、ビューとJSの記述を以下のように変更します。

<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字を超えた時点で文字が赤に変わってしまいます。そこで、文字数制限も取得して関数に組み込みます。

<!--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を使わず要素を特定できるようにしてみます。

<!--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

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

0
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
0
0