116
106

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

フォーム内でonclick属性を使う時には、name / idに気をつけよう

Last updated at Posted at 2015-11-04

はじめに

form周りのコードを書いていたところ、思わぬ動作に遭遇しました。基本的な知識かもしれませんが、知らなかったので備忘録がてらメモしたいと思います。

結論

さっそく結論を書いてしまうと、<form>タグ内においてフォーム部品(inputなど)のnameやidと、onclick属性で呼び出すユーザ定義関数名が重複していると関数が実行されないというものです。

名前が重複していなかったり、element.onclick = function() {}.on()でイベントを設定していれば避けられるので、遭遇する機会は少ないかもしれません。ですがせっかくなので、これに至るまでの道のりを簡単に残したいと思います。。。

動作はchrome 46.0.2490.80で確認しました

鳴らない、電話

(実際のものから相当省略していますが)以下のようなコードを書いていました。
とりあえず動作を確認しようと思い、onclick属性で関数を実行させようとしました。

index.html
<script>
  function callPhone() {
    console.log('ジリリリ...');
  }
</script>
<form action="" onsubmit="return false;">
  <input type="submit" name="callPhone" onclick="callPhone();" value="着信あり">
</form>

一向に電話は鳴りません。

はて?と思いDevtoolsでコンソールを見ると以下のように表示されています。

Uncaught TypeError: callPhone is not a function

関数じゃない・・・?
よくいみがわかりませんでした。

色々試してみる

何が返ってきているのか

関数じゃないなら何なんだ!
ということで、まずはconsole.log()してみました。

index.html
<!-- 略 -->
<input type="submit" name="callPhone" onclick="console.log(callPhone);" value="着信あり">
コンソール.
<input type="submit" name="callPhone" onclick="console.log(callPhone);" value="着信あり">

自分自身が返って来ていました。
念のためinputのすぐ下に<script>console.log(callPhone);</script>を仕込みましたが、こちらは意図した通りfunction()が返って来ました。

グローバルにアクセスしてみる

次にcallPhone()はグローバルにしていたので、直接グローバルにアクセスしてみました。

index.html
<!-- 略 -->
<input type="submit" name="callPhone" onclick="window.callPhone();" value="着信あり">
コンソール.
ジリリリ...

電話が鳴りました!

つまりcallPhone();だけだと、グローバルより前で発見されたと考えられます。onclick属性はこんな動作だったかな・・・?

要素を変更してみる

inputタグから別の要素に変えてみます。

index.html
<!-- 略 -->
<p onclick="callPhone();">着信あり</p>
コンソール.
ジリリリ...

電話が鳴りました!

・・・

あ、name属性がいけないのかな?

index.html
<!-- 略 -->
<p name="callPhone" onclick="callPhone();">着信あり</p>
コンソール.
ジリリリ...

鳴った!

うーん、どうもinputの時だけ鳴らないようだ。

inputでname属性を変えてみる

inputタグのname属性を少し変更してみます。

index.html
<!-- 略 -->
<input type="submit" name="callPhone_" onclick="callPhone();" value="着信あり">
コンソール.
ジリリリ...

鳴った!

だんだん分かってきました。念のため**name="callPhone"**に戻してみると鳴らなくなりました。

もちろんname自体を削除しても関数が実行されるようになります

さらに色々試してみる

気になって色々と試してみると、以下のことが分かりました。

  • inputの他にもselecttextareabuttonなど、いわゆるフォーム部品のタグで同じ挙動になった
  • typeは関係無かった(textでもradioでも同じ)
  • フォーム部品であっても、<form>外に配置すると一転、関数が実行されるようになった
  • name属性だけでなく、idでも同じ挙動になった

以上のことから、<form>内の部品要素のnameやidと、onclick属性で呼び出す関数名が重複していると意図した関数が実行されない、との結論に至りました。

終わりに

しかし何でなんだろうなぁと思っていたところ、stackoverflowにズバリその答えが書いてありましたw

Why JS function name conflicts with element ID?
http://stackoverflow.com/questions/9158238/why-js-function-name-conflicts-with-element-id

簡単に言うと、チェインによりthis.formが自動的かつ優先的に、見つかっていたということのようです。
またstackoverflowでは、onchange属性について書かれているので、onclickだけでなく色んなonXXXX属性で発生しそうです(onclick以外は未確認です)。

index.html
<!-- true -->
<input type="submit" name="callPhone" onclick="console.log(callPhone === this.form.callPhone);" value="着信あり">
116
106
1

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
116
106

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?