この記事は以下の記事の続きとなります。
【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属性を記述しました。
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>
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>
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の記述によっては反映されないので注意が必要そうです。
機能実装後の質問投稿画面
質問タイトルは50字を超えて数字が赤色になっていますが、質問内容詳細は400字以内なので黒色のままです。