1. insight3110

    Posted

    insight3110
Changes in title
+twitter typeaheadはいろいろ改良されていた
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,173 @@
+Bootstrap内にもauto complete機能としてtypeaheadがあるが、日本語の扱いに難があるみたい。
+[Bootstrap Typeaheadの日本語入力対応 | PLUS](http://plus.vc/web/javascript/6376/)
+[ARKの技術メモ: [Twitter Bootstrap]typeaheadでの日本語入力問題への対策](http://arkmemo.blogspot.jp/2013/03/twitter-bootstraptypeahead_26.html "ARKの技術メモ: [Twitter Bootstrap]typeaheadでの日本語入力問題への対策")
+
+だが、Bootstrap内とは別にtwitter制作のtypeaheadライブラリがあり、これを使用してみると日本語問題はないっぽい。しかも、機能も強化されている。
+[twitter/typeahead.js](https://github.com/twitter/typeahead.js "twitter/typeahead.js")
+[typeahead.js – examples](http://twitter.github.io/typeahead.js/examples/ "typeahead.js – examples")
+
+そこで、いくつかサンプルを。
+
+## データ埋め込みサンプル
+もっとも簡単に、データを直接埋め込むサンプル。
+CSSは[jharding/typeahead.js-bootstrap.css](https://github.com/jharding/typeahead.js-bootstrap.css "jharding/typeahead.js-bootstrap.css")から拝借。
+
+```html:
+<!DOCTYPE html>
+<link href="bootstrap.min.css" media="screen" rel="stylesheet" type="text/css" />
+<link href="typeahead.js-bootstrap.css" media="screen" rel="stylesheet" type="text/css" />
+<div class="container">
+ <h1>テスト</h1>
+<input type="text" class="ta" name="name">
+</div>
+<script src="jquery.js" type="text/javascript"></script>
+<script src="typeahead.js" type="text/javascript"></script>
+<script src="sample.js" type="text/javascript"></script>
+```
+
+```js:sample.js
+$(function() {
+ return $('.ta').typeahead({
+ name: 'names',
+ local: ["斉藤", "斉木", "大野", "大原"],
+ limit: 10
+ });
+});
+```
+![type1.png](https://qiita-image-store.s3.amazonaws.com/0/26556/ef744162-f9c1-4f0f-ad4a-b756d2cce657.png)
+・・・動いた
+
+## jsonで別ファイルに持つサンプル
+以後は、サーバー上でないと動かない。
+まず、データファイルはjson形式で別に持つことができる。
+
+```json:
+[
+ {
+ "value":"斉藤",
+ "tokens":["さいとう","saito"]
+ },{
+ "value":"斉木",
+ "tokens":["さいき","saiki"]
+ },{
+ "value":"大野",
+ "tokens":["おおの","oono"]
+ },{
+ "value":"大原",
+ "tokens":["おおはら","oohara"]
+ }
+]
+```
+ここで、
+* valueは、実際にテキストボックスに入る値
+* tokensは、入力された文字列に反応させたい値を配列で入れる。
+上記の例では、「斉藤」は、「さいとう」でも、「saito」でもヒットするように設定している。
+これを、サーバー上の適当な場所に保存(ここではルートに保存)
+
+```js:sample.js
+$(function() {
+ return $('.ta').typeahead({
+ name: 'names',
+ prefetch: '/sample.json',
+ limit: 10
+ });
+});
+```
+
+(htmlはそのまま)
+
+![type2.png](https://qiita-image-store.s3.amazonaws.com/0/26556/ca88c9c4-8bc3-cb1f-6903-bed4c271b5b4.png)
+![type3.png](https://qiita-image-store.s3.amazonaws.com/0/26556/de40b0ef-59b0-5cc5-b399-75363ef6990b.png)
+できた。
+
+## idもhiddenフィールドとして保存したい
+これまでのサンプルのようなユーザーデータで、ユーザーごと名前をテキストボックスに
+保存するだけでなく、IDも一緒に保存したいとする。ついでに、部署情報も追加して
+テンプレートシステムを利用してみる。テンプレートエンジンは、本家にならって
+[twitter/hogan.js](https://github.com/twitter/hogan.js "twitter/hogan.js")
+を利用してみる。
+用意したサンプルのjsonは以下の通り。
+
+```json:
+[
+ {
+ "value":"斉藤",
+ "id": 1,
+ "busho": "営業部",
+ "tokens":["さいとう","saito"]
+ },{
+ "value":"斉木",
+ "id": 2,
+ "busho": "経理部",
+ "tokens":["さいき","saiki"]
+ },{
+ "value":"大野",
+ "id": 3,
+ "busho": "営業部",
+ "tokens":["おおの","oono"]
+ },{
+ "value":"大原",
+ "id": 4,
+ "busho": "管理部",
+ "tokens":["おおはら","oohara"]
+ }
+]
+```
+htmlも、以下のように、IDを保持するためのhidden属性のinputを用意する
+
+```html:
+<input class="ta" name="prefs" type="text" />
+<input id="hidden_id" name="id" type="hidden" />
+```
+
+javascript部分も以下のように変更。
+
+```js:sample.js
+$(function() {
+ return $('.ta').typeahead({
+ name: 'name-busho2',
+ prefetch: '/sample.json',
+ template: '<div style="width:10em"><p style="float:right">{{busho}}</p><p>ID:{{id}}</p><p style="font-weight:bold">{{value}}</p></div>',
+ engine: Hogan
+ }).on("typeahead:selected typeahead:autocomplete", function(e, datum) {
+ return $('#hidden_id').val(datum.id);
+ });
+});
+```
+
+ここで、name属性は一応変更(任意の値でいいみたい)。
+また、templateではヒットしたものをどのように表示するのか、ここで自由に指定できる。内容は普通のHTMLで、コード中に{{属性の項目名}}で、その項目名を埋め込むことができる(この表記はテンプレートエンジンHoganの表記法)。この自由さがtwitter typeaheadの魅力だと思う。Bootstrapのtypeaheadでもできるにはできたが、面倒だったはず。これで、valueとIDだけでなく、自由に項目を追加、扱うことができる。
+
+実際に選んだあとの処理は、カスタムイベントの`typeahead:selected`と`typeahead:autocomplete`が定義されているので、そのイベント発生時の処理を`on("typeahead~`以下に記述する。
+functionはeとdatumの2つの引数をとるが、datumに、実際選ばれたオブジェクトの情報が入っている。idは`datum.id`でとれるので、あとは普通に所定のものにセットするだけ(部署情報はdatum.bushoなど、ほかの値も自由にとれる)
+
+実際の画面はこんな感じに。
+![type4.png](https://qiita-image-store.s3.amazonaws.com/0/26556/89cfb212-818d-f820-abb3-63246b8c3068.png)
+firebugでhidden_idを見ると、更新されている。
+![type5.png](https://qiita-image-store.s3.amazonaws.com/0/26556/e5cf08fa-bc8d-51b7-4cdd-7aa94b14fd9c.png)
+
+## リモートでやり取りしたい
+ここまでくると簡単で、javascriptコードの
+`prefetch: ~`
+の部分を
+`remote: "/usr/find/%QUERY"`
+に変更するとajax通信をする。タイプされた内容は`%QUERY`の中に入る。なので、単純に
+`remote: "/usr/find?name=%QUERY"`
+とすると、params[:name]でタイプされた内容をサーバー側で補足することができる。
+もちろん、サーバーからの返事はjsonが無難。
+また、上記のremote設定は簡略版で、詳細版はremote部分を
+```js:
+remote: {
+ url: '/states?q=%WILDCARD',
+ wildcard: '%WILDCARD',
+ rateLimitFn: 'throttle',
+ rateLimitWait: 300, // rateLimitWait or wait? i think i prefer the former
+ maxConcurrentConnections: 4,
+ dataType: 'json',
+ timeout: 2000,
+ cache: true,
+ beforeSend: function(jqXhr, settings) { /* set headers, etc. */ },
+ filter: function(resp) { /* parse suggestions out of response */ }
+ }
+```
+このようなオプションを指定することができる。