mizky(^ω^) なぜかループの最初の要素だけ、JavaScriptが正常に動作する。。。
こんにちは、mizkyです。
今回はDjangoでJavaScriptを使用していた際に遭遇した現象にについて、共有します。
今回の問題
Djangoのテンプレートを使用していた際、JavaScriptを活用してページの要素を操作しようとしたところ、想定外の挙動に遭遇しました。
具体的には、forループを利用して複数のHTML要素を生成している中で、
それぞれの要素に同じIDを割り当ててしまった結果、
JavaScriptがループの最初の要素にしか動作しないという問題が発生しました。
簡単なサンプル
まず、Djangoテンプレートでのサンプルコードです。
{% for item in items %}
<div id="item">{{ item.name }}</div>
{% endfor %}このテンプレートでは、各アイテムに対して同じID「item」が付与されています。
そして、以下のJavaScriptを使ってこれらの要素を操作しようと試みます。
var itemDiv = document.getElementById('item');
itemDiv.style.color = 'red';このJavaScriptコードの意図は、ループで生成されたすべての要素を赤色にすることです。
しかし、実際にはgetElementById()がページ上で最初に見つかった要素にのみアクセスするため、
期待した通りに動作しません。
結論
テンプレートについて、for文を使用せずに書き直すと
<div id="item">{{ item.name }}</div>
<div id="item">{{ item.name }}</div>
<div id="item">{{ item.name }}</div>このようになっており、全てのdiv要素に同じIDが付与されてしまっています。
JavaScriptでgetElementById()を使用すると、このメソッドはページ上で最初に見つかった要素のみを返すため、今回のような現象が発生しました。
当たり前ですが、ID属性はそれぞれの要素に固有でなければなりません。
具体例
問題の再現
一応、Djangoのテンプレートを使用せずに、HTMLとJavaScriptだけで同現象を再現してみます。
下記に、今回使用するサンプルコードを示します。
<!DOCTYPE html>
<html>
<head>
<title>ID Test</title>
</head>
<body>
<div id="unique">このテキストは変更されますか?</div>
<div id="unique">このテキストは変更されますか?</div>
<script>
// 同じIDを持つ要素にアクセス
var element = document.getElementById('unique');
element.textContent = '最初の要素のテキストが変更されました!';
</script>
</body>
</html>実際にブラウザに表示してみます。

ボタンを押下すると、、、

確かに、最初の要素だけ変わることが分かりました。
対策
IDではなく、Classで正常に実行されるか確認します。
下記に、Classを使用して書き直したサンプルコードを記載します。
<!DOCTYPE html>
<html>
<head>
<title>ID Test</title>
</head>
<body>
<div class="unique">このテキストは変更されますか?</div>
<div class="unique">このテキストは変更されますか?</div>
<button onclick="changeText()">テキストを変更</button>
<script>
function changeText() {
var elements = document.querySelectorAll('.unique');
for (var i = 0; i < elements.length; i++) {
elements[i].textContent = 'このテキストは変更されました!';
}
}
</script>
</body>
</html>
属性をIDからclassに変更しました。
また、textContentをループ処理させています。
挙動を確認してみます。

「テキストを変更」ボタンをクリックすると、

全ての文言が正常に変更されました。
まとめ
本記事では、DjangoテンプレートでHTML要素を生成する際に同じIDが複数の要素に付与される問題を掘り下げました。
問題回避のためのポイントは次の通りです
- IDの一意性を守る:各要素にはユニークなIDを割り当てます。
- クラスの活用:共通の属性を持つ要素はクラスで管理します。


コメント