Javascriptからsubmit()関数でフォーム送信できない問題

Mixpanelをセットアップ中のエンジニアからのヘルプでハマりこんだ問題について。

mixpanel.track_formsでフォーム送信をトラッキングしたい

Mixpanelには、フォーム送信をフックして、ユーザーがフォーム送信したことをトラッキングする機能があるようです。

mixpanel.track_forms

track_forms関数を使って、対象のフォームに対してイベントをしかけます。この処理はフォームの送信をフックして、Mixpanelへトラッキング情報を送信します。そして、送信のコールバックで本来のフォーム送信を実行するというものです。

コールバックを待って本来の処理を実行するのではMixpanelのレイテンシが高くなるとサービスの動作に影響を与えるのではという心配がありますが、そこは300msくらいのしきい値でMixpanelへの送信をあきらめる機構も入っているそうです。

トラッキング後に本来のフォーム送信ができない

この関数を使うことで確かにMixpanelにトラッキング情報の送信ができました。が、本来のフォーム送信の動作が動かなくなりました。

エラー内容は以下。

TypeError: Property 'submit' of object #<HTMLFormElement> is not a function

Mixpanelのソースを流して読みすると、該当のコードは大雑把に以下のようなものです。

$('form').each(function(){
    this.submit();
});

問題のソースコード

この現象を検証するために、HTMLを書きました。

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8" />
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
    </head>
    <body>
    	<form>
    	    <input type="text" name="nickname" value="" />
    	    <input type="submit" name="submit" value="SUBMIT" />
        </form>
    </body>
</html>

これは動かない例なのですが、ごくありふれたformです。中に入力フォームと送信ボタンを置いています。

問題の原因は、送信ボタンにname=”submit”をつけていたことのようでした。どこでこの癖をつけてしまったのか覚えてないですが、僕は石器時代からつけていたような記憶があります。

formの中にsubmitというnameをもつ要素を置くと競合する

先のMixpanelの一部のコードはもっと簡単に書くと以下のような形になります。

$('form').get(0).submit();

そしてこれは以下のようなエラーを吐きます。

TypeError: $(...).get(...).submit is not a function

Chromeだと以下のようなエラー。

TypeError: Property 'submit' of object #<HTMLFormElement> is not a function

これはなぜかというと、Javascriptのform変数の中のsubmit変数が、submitというname属性をもつフォーム要素によって上書きされてしまうことにあります。

実際にsubmitオブジェクトを吐かせてみます。

console.info($('form').get(0).submit);

<input type="submit" value="SUBMIT" name="submit">

submit変数が関数ではなく、フォーム要素になってしまっています。

submitというname属性をもつフォーム要素を置かない

正しくはこうです。

<form>
    <input type="text" name="nickname" value="" />
    <input type="submit" value="SUBMIT" />
</form>

これでMixpanelの方も、無事に動きました。

この悪しき癖を早期に直したいと思います・・・。

About katty0324

One comment

Leave a Reply

Scroll To Top