ラベル AJAX の投稿を表示しています。 すべての投稿を表示
ラベル AJAX の投稿を表示しています。 すべての投稿を表示

2013年3月26日火曜日

[Twitter Bootstrap]typeaheadでの日本語入力問題への対策

[Twitter Bootstrap]typeaheadの項目をajaxで取得するコード例

上記の記事にて、日本語入力に問題ないと書きましたが嘘でした。

現状、問題を二つ発見しました。一応対処できたのでシェアします。

1.日本語を入力し、文字変換確定のEnterを押すと、その間に表示されていたtypeahedの候補を選択したことになってしまう。(Safari5.1.7で発生。chrome25.0.1364.172 mは問題なかった。)


【問題内容】

 A.キーボード入力開始
     ↓
 B.一つのキーを押すごとに候補が表示されていく。一番上の候補が選択状態となる。
     ↓
  C.文字変換確定のためにEnterキーを押す。
     ↓
 D.Bで表示されていた候補の一番上のものが選択され、テキストボックスに入ってしまう。

例として私の開発環境での事例を紹介する。
「ファ」と入力した段階(まだ候補確定のEnterキーは押していない)では、typeaheadの候補としては、「ファッション」、「メンズファッション」が表示され、一番上の「ファッション」が選択れた状態だった。
そこで、「ファ」を確定させるためEnterキーを押すと、「ファッション」とテキストボックスに入ってしまうのだ。「ファ」と入力したいだけなのに。

【対処方法】

1.Bで表示される候補のうちどれも選択されないようにする。

  このサイトを参考にさせていただいた。
 Bootstrap Typeaheadの日本語入力対応
 このサイトに書いてあるbootstrap.jsのある部分をコメントアウトする。
 ただし、私の場合、これだけだと足りなかった。
 確かに、Bで一つも選択状態になっていない候補が表示されるのがだ、CでEnterを押すと、テキストボックスが空になってしまう。おそらく、0文字の候補を選択してEnterを押したように解釈されてしまうのだろう。そこで以下の対処も行った。

2.オプションのupdaterを選択した候補が0文字だったらqueryを返すようなロジックにする。

下記の10~16行目を追加した。 これで、Enterを押しても空欄とならず、入力しようとしていた文字列が入ってくるようになった。
※7~9行目のsorterが気になる方は「[Twitter Bootstrap]typeaheadがせっかくサーバ側でソートした配列をソートし直しちゃう件への対処 」をご覧下さい。

$("#tagSelectInput").typeahead({
    source: function(query, process) {
        $.post($("#tagSelectInput").attr("data-url"), { 'data[Tag][content]': query}, function(data) {
            process(JSON.parse(data));
        });
    },
    sorter:function(items){
        return items;
    },
    updater:function(item){//選択してない状態でenter押すと、空欄になってしまうので。
        if(item.length==0){
            return this.query;
        }else{
            return item;
        }
    }
});

2.日本語入力にて文字列入力中も変換確定のEnter押下時もtypeahedの候補が表示されない。(FireFox19.0.2で発生。safari、chromeはOK)


【対処方法】

bootstrap.jsのEnterを押した時のイベントの部分に、明示的に候補を探してくるコマンドを入れた。(1950行目あたり。)
以下でいうと12~15行目あたりを修正した。もともとここに、this.lookup()はなかった。FireFoxのためにここにこれを入れてしまうと、正常に動いているブラウザでは一回余計に検索をかけにサーバ側にアクセスしてしまうかなと心配したが、なぜかアクセス回数は増えずに済んだ。 もし増えたら、ブラウザの種類を判定してFireFoxだけ行うようにしようと思っていたが。

 , keyup: function (e) {
    switch(e.keyCode) {
      case 40: // down arrow
      case 38: // up arrow
      case 16: // shift
      case 17: // ctrl
      case 18: // alt
        break

      case 9: // tab
      case 13: // enter
        if (!this.shown){
            this.lookup();
            return;
        }
        this.select()
        break

      case 27: // escape
        if (!this.shown) return
        this.hide()
        break

      default:
        this.lookup()
    }

    e.stopPropagation()
    e.preventDefault()
}
上記の対処で違和感なく動くようになっています。ついでにIE8でみたけど問題なかったです。
ちなみにbootstrapはbootstrap-transition.js v2.2.2です。

以下と合わせて読めば、Bootstrapのtypeahedをajaxで日本語入力で使うのにお役に立つかと思います。

[Twitter Bootstrap]typeaheadの項目をajaxで取得するコード例
[Twitter Bootstrap]typeaheadがせっかくサーバ側でソートした配列をソートし直しちゃう件への対処 


【その他参考ページ】
Getting More From Twitter Bootstrap’s Typeahead Library
How to Use JSON Objects With Twitter Bootstrap Typeahead

2013年3月25日月曜日

[Twitter Bootstrap]typeaheadがせっかくサーバ側でソートした配列をソートし直しちゃう件への対処

[Twitter Bootstrap]typeaheadの項目をajaxで取得するコード例

上記の記事で紹介したajaxでの候補の取得方法だが、このままだと自分の場合ちょっとした問題がある。
サーバ側でどのように候補を検索するかというと、たいていSQLのセレクト文で抽出するはず。その際、order by句を使って、順序付けを普通はすると思う。

このようにせっかく順序付けをしてもブラウザ側でtypeaheadがご丁寧にソートしなおしてしまうのだ。

例えば、「ファ」と入力した段階だと、typeahedがサーバ側に「ファ」を送信。
サーバ側で、SQLで検索。select文にorder by句をつけて。
それで、「メンズファッション」「ファッション」という順番でjson形式のデータを返す。
これは、サーバ側のSQLのorder byでついた順序だ。

しかし、ブラウザ側でそのjsonをうけとったら、ご丁寧にもソートしなおしてくれて、「ファッション」「メンズファッション」という順番にしてしまう。
これは、マッチした部分が文字列の頭のほうにあるものが上に来るロジックらしい。

これを抑止するために以下のようにsorterオプションを、単純に受け取った配列をそのまま返すようなロジックで上書いたら、サーバ側でつけた順番どおりに「メンズファッション」「ファッション」と表示されるようになった。


$("#tagSelectInput").typeahead({
   source: function(query, process) {
      $.post($("#tagSelectInput").attr("data-url"), { 'data[Tag][content]': query}, function(data) {
         process(JSON.parse(data));
      });
   },
   sorter:function(items){
      return items;
   }
});

[Twitter Bootstrap]typeaheadの項目をajaxで取得するコード例

Twitter Bootstrapのtypeaheadだけど、ajaxでアイテムをサーバ側で検索して取得するのが普通だと思う。
だけど、本家のサイトだとajaxを使用したサンプルが全く無いので、かなり厳しい。

そこで探していたら、英語だけどコード例を載せている人がいました。
Getting More From Twitter Bootstrap’s Typeahead Library

自分は一番上に出ているサンプルを少し修正して実現しきました。
("q"は自分がサーバ側で指定した名前に変更。limitはサーバ側で行うので削除)

サーバ側では、検索した結果を連想ではない普通の配列に入れて、json形式で返してあげればOKです。

また、心配していた日本語での動作ですが、特に修正せずに問題ない挙動です。

思った以上に楽だった!

【追記2013/3/26】
日本語入力に関して色々と問題がみつかったので、以下の記事で対処しています。ご覧下さい。
[Twitter Bootstrap]typeaheadでの日本語入力問題への対策

2013年2月12日火曜日

[Bootstrap]簡単にmodalにajaxでコンテンツを取得するスクリプト

http://twitter.github.com/bootstrap/javascript.html#modals 

ここで紹介されている方法だと、html内にdiv要素で枠組み準備しておかなかったりと、面倒くさいので以下のスクリプトを使うことにした。非常に簡単。

Dynamic (AJAX) loaded Bootstrap Modal (Bootstrap 2.1)




2012年12月20日木曜日

[AJAX]ajaxで取得したレスポンス内のjavascriptはデバッグできないので

Ajaxで取得したHtml等の中に書かれているjavascriptはFirebugなどで
デバッグすることができない。

なので、なるべくソースはもともとあるjavascript(Ajaxではなく最初にそのページを
表示した際に読み込まれるjavascript)内に関数として記述しておき、Ajaxで取得した
javascriptからはその関数を呼び出すだけ、という形にしておけば、デバッグが可能だ。

2012年10月10日水曜日

[CakePHP]$js->submit()のoptionsのbeforeの限界と対策

以下のような形でbeforeオプションを使用し、
ajax送信直前に送ろうとしているformの値自体を操作しようと
したのだけど、うまく送れなかった。
おそらく、beforeが完了してから送信の処理が開始されるので
はなく、beforeと同時並行的に送信するデータ自体は取得して
いるからだろう。

echo $js->submit("登録する",array(
    'id'=>'register',
    'url'=>'add',
    'update'=>'#complete'
    'before'=>'
        var fm = document.getElementById("add");
        $("#add").append("<input type=\"hidden\" name=\"data[Theme][explanation]\"/>");
        fm.elements[\'data[Theme][explanation]\'].value=$("#explanation").val();
    '
));

では、どうすればよいか。
beforeで設定するのではなく、別で$js->submitより上に、
onclickのイベント設定をしてしまえばよい。
こうすれば、フォームの値の操作が完了してから、
送信の処理が開始されるようになる。

$js->get("#register")->event('click','
    var fm = document.getElementById("add");
    $("#add").append("<input type=\"hidden\" name=\"data[Theme][explanation]\"/>");
    fm.elements[\'data[Theme][explanation]\'].value=$("#explanation").val();
');

echo $js->submit("登録する",array(
    'id'=>'register',
    'url'=>'add',
    'update'=>'#complete'
)); 
※CakePHPのバージョンはcakephp-cakephp-1.3.15-9-gacd25c3.zip