らくらくホンでクリックイベントが取得できない問題をめぐる戦いと敗北の記録


目次

この記事では暫定的な解決を行いましたが、根本的には 未解決 です。
【この記事でわかること】

  • らくらくホンでクリックイベントが取得できない問題
  • 問題を解決 できなかった 方法
  • 暫定的な解決方法

はじめに

「らくらくホン」という存在をご存知でしょうか。
らくらくホン(らくらくスマートフォン)はNTTドコモから発売されている、簡単操作がウリのシリーズです。
auだと「かんたんケータイ」に相当するこのシリーズは、主に複雑な操作を苦手とするシニア向け端末として提供されています。

参考:

利用者にとっては
「文字が大きくて見やすい」
「ボタンが大きくて押しやすい」
「複雑な操作が不要」
といった特徴をもつこれらのシリーズは、サービス開発者にとっては表示が崩れたり、予期せぬ動きをしたりしなかったりと、難関となることがあります。

JavaScriptでクリックイベントが取得できない

今回のハマりがこちら。クリックイベントが取得できない問題です。
すべてのらくらくホンで発生するわけではありません。
今回の環境はF-06Fを利用しました。: らくらくスマートフォン3 F-06F

こんな感じの簡単なページがあったとします。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>らくらくホンテスト</title>
  </head>
  <body>
    <p>年齢: <input type="number"></p>
    <p>好きな食べ物: <input type="text"></p>
    <button>送信</button>
  </body>
</html>

サンプルページ

このままだと、「年齢」のinputの中にマイナスの数が入れられてしまうかもしれません。
え、最初から select タグ使ったらいいじゃんって? ま、まあそうなんですけどこれはサンプルなので。

その他にも「好きな食べ物」が空のまま送信ボタンが押されてしまうかもしれません。
そういった場合に、JavaScriptで入力値が正しいかどうかを判定(バリデーション)したいときがあります。

判定して、問題がなければ後続処理(サーバに送信して永続化するなど)を行い、入力値に問題があればどこが間違っているのかを表示して再入力を促したりするやつです。
間に通信を挟まなくていいので、フロント側で対応できるならしてしまいたいです。

ブラウザのJavaScriptが有効(ON)状態になっていることを確認します。

jQueryの.click(function()) →失敗

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>らくらくホンテスト</title>
        <script src="https://code.jquery.com/jquery-3.6.1.slim.min.js" integrity="sha256-w8CvhFs7iHNVUtnSP0YKEg00p9Ih13rlL9zGqvLdePA=" crossorigin="anonymous"></script>
        <script>
            jQuery(document).ready(function(){
                $(".js-btn-click").click(function(){
    
                    // 判定処理
                    alert("判定");
    
                });
            });
        </script>
    </head>
    <body>
        <p>年齢: <input type="number"></p>
        <p>好きな食べ物: <input type="text"></p>
        <button class="js-btn-click">送信</button>
    </body>
</html>

button タグに js-btn-click クラスをつけ、clickイベントを拾います。
イベントがキックされたのをわかりやすくするために alert を入れておきます。 PCブラウザで試してみると問題なくアラート表示が行われます。

jQueryサンプル

が、らくらくホン(F-06F)でボタンを押しても無反応。スン…としてます。
ええい、次です。

プレーンなJavaScriptのonclick属性 →失敗

jQueryがダメなのか? と推測してプレーンな書き方でやってみましたが、こちらも失敗。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>らくらくホンテストプレーンなやつ</title>
        <script>
            function btnClick(){
                // 判定処理
                alert("判定");
            }
        </script>
    </head>
    <body>
        <p>年齢: <input type="number"></p>
        <p>好きな食べ物: <input type="text"></p>
        <button onclick="btnClick()">送信</button>
    </body>
</html>

もちろん、PCブラウザや一般的なandroid, iOSでは動作します。
(「らくらくホン以外の全てのandroidで動作する」という保証はありません)

タッチイベントを使う →失敗

よかろう、ならばタッチイベントだ。
タッチイベントはW3Cが仕様草案をまとめており(参考: W3C: Touch Events)、スマートフォンなどのタッチ系デバイスのブラウザで実装されているものです。
今回使えそうなものは下記のふたつ。

  • touchstart
  • touchend

タッチイベントはonclickのように標準で使えるようになっていないので、 addEventListener を使ってイベントリスナーに登録しなければなりません。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>これならどうだ、らくらくホンテスト</title>
    </head>
    <body>
        <p>年齢: <input type="number"></p>
        <p>好きな食べ物: <input type="text"></p>
        <button id="btn">送信</button>
    </body>

    <script>
        // DOMを先に生成してもらうためにbodyの下に書いています
        // このvarがletやconstならうまくいく、なんてこともないです
        var element = document.getElementById('btn');
        element.addEventListener('touchstart', function(event) {

            // 判定処理
            alert("判定");

        }, false);
    </script>
</html>

touchstartイベントは指を置いた(タッチした)瞬間に発火し、touchendイベントは指を離した(タッチが終わった)タイミングで発火します。
注意が必要なのは、touchendの判定は 指を離した場所 ではなく 指を置いた場所 に依存していることです。

  • ボタンをタッチし、指を動かしてから、ボタンじゃない場所で指を離す → ボタンのtouchendイベントが発火する
  • ボタンではない場所をタッチし、指をボタンの上に動かしてから離す → ボタンのtouchendイベントは発火しない

まあどちらにせよ「らくらくホン」では発火してくれなかったんですが。

タッチイベントと同じように、clickイベントを addEventListener で追加してみても同様の結果に終わりました。

buttonからa要素に変えてみる →失敗

<button> 要素との相性が悪い可能性も考慮し、 <a> 要素に変更してみました。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>DOM変更</title>
        <script src="https://code.jquery.com/jquery-3.6.1.slim.min.js" integrity="sha256-w8CvhFs7iHNVUtnSP0YKEg00p9Ih13rlL9zGqvLdePA=" crossorigin="anonymous"></script>
        <script>
            jQuery(document).ready(function(){
                $(".js-btn-click").click(function(){
    
                    // 判定処理
                    alert("判定");
    
                });
            });
        </script>
    </head>
    <body>
        <p>年齢: <input type="number"></p>
        <p>好きな食べ物: <input type="text"></p>
        <a class="js-btn-click">送信</a>
    </body>
</html>

が、これでもクリックイベントは所得できませんでした。
リンク先を設定すれば遷移はできるので、押せていないわけではないようなのですが。

暫定的な解決

解決策というか厳密には解決できていないんですが、判定をサーバ側で行うことにして回避しました。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>くやしい</title>
    </head>
    <body>
        <form action="宛先url" method="post">
            <p>年齢: <input name="age" type="number"></p>
            <p>好きな食べ物: <input name="food" type="text"></p>
            <input type="submit" value="送信">
        </form>
    </body>
</html>

form のsubmitにしてやればサーバ側への送信は問題なく行えます。
ただ、この場合でもclickイベントは発火しないのでsubmitされる前に判定をしたり、submitをキャンセルしたりはできませんでした。なんでや。

仕方ないのでサーバ側で受け取った情報を精査し、うまく入力されていればそのまま後続処理を行い、問題があればエラーメッセージと共に元のurlに戻す。
その際、入力された値がクリアされているとユーザさんフレンドリィでないので、元の入力値も復元しておき――とまぁなんともまわりくどい。通信させてページを読み込む時間もかかります。

らくらくホン専用のサービスならこの対応でも致し方ないですが、他の端末にも対応したサービスである場合は、コードを出し分けるなどの工夫が必要になってくると思います。

俺たちの戦いはまだ始まったばかりだ――!!!

できればもうらくらくホンとは戦いたくないです。