質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
jQuery UI

jQuery UI はjQuery公式のインターフェースライブラリであり、対話型のウェブアプリケーションを作る際に役立ちます。

CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

Q&A

解決済

3回答

5482閲覧

CakePHP+jQuery UIでのオートコンプリート

seagal18

総合スコア32

jQuery UI

jQuery UI はjQuery公式のインターフェースライブラリであり、対話型のウェブアプリケーションを作る際に役立ちます。

CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

0グッド

2クリップ

投稿2015/10/28 05:06

編集2015/10/29 08:23

■目的
CakePHPでWebシステムを構築中です。
あるデータテーブルAの検索フォームにて、マスタテーブルBのnameフィールドに入っているデータをオートコンプリートで補完入力したいです。

■開発環境
CakePHP 2.7.3
PHP 5.6.8
jQuery 1.11.3
jQuery UI 1.11.4

■参考にしたサイト
http://junichi11.com/?p=423
http://www.buildinsider.net/web/jqueryuiref/0019
http://js.studio-kingdom.com/jqueryui/widgets/autocomplete

■実装手順

  1. jqueryとjquery UIをレイアウトファイルで指定。

  2. テーブルAのコントローラに、オートコンプリートのデータを取得するメソッドを追加。

TableAController.php

php

1public function autocomplete(){ 2 $this->loadModel('TableB'); 3 $field = 'name'; 4 $term = $this->params['url']['term']; 5 // 入力値 無:全てのデータの中から10件返す。 6 // 入力値 有:入力値を含むデータを10件返す 7 $condition = array(); 8 if(!empty($term)){ 9 $condition = array('TableB.'.$field.' like' => "%".$term."%"); 10 } 11 12 $query = array( 13 'fields' => array($field), 14 'conditions' => $condition, 15 'limit' => 10, 16 'order' => array('TableB.'.$field => 'ASC'), 17 'group' => $field, 18 ); 19 20 $data = array(); 21 $items = $this->TableB->find('all', $query); 22 23 foreach ($items as $item) { 24 $cnt = array_push($data, $item['TableB'][$field]); 25 } 26 27 // JSON形式の文字列を生成 28 $json = json_encode($data); 29 echo $json; 30} 31

この時点でautocomplete()メソッドの動作確認をしました。

http://localhost/cakephp/TableA/autocomplete?term=hoge

このURLにアクセスすると、テーブルBからnameフィールドに"hoge"が含まれるレコードがJSON形式で返ってくることが確認できています。

  1. テーブルAのビューにjavascriptとテキストボックスを作成。

TableA/index.ctp

php

1<script type="text/javascript"> 2$(function(){ 3 $('#autocomplete').autocomplete({ 4 source: '/TableA/autocomplete', 5 autoFocus: true, 6 delay: 500, 7 minLength: 2 8 }); 9}) 10</script> 11 12<?php echo $this->Form->input('name', array( 13 'type' => 'text', 14 'id' => 'autocomplete', 15)); ?>

これでテキストボックスが作成されますが、入力してもオートコンプリートが動作しません。
2.の時点でautocomplete()メソッド自体は正常に動作している(と思われる)ので、怪しいのはjavascriptかと思っています。
特にsource: '/TableA/autocomplete',の部分が、ちゃんとしたURLを参照できているのかが疑わしいです。
しかし実際のところどういう動作をしているのか確認する方法が分からず、詰まっています。


2015/10/29追記

ipadcaronさんのアドバイスを元にシンプルな構成で検証してみました。
CakePHPでの動作は一旦忘れて、htmlとphpだけで構成してみました。

json_echo.php

php

1<?php 2 echo '[{"id":"1","value":"item1"},{"id":"2","value":"item2"},{"id":"3","value":"item3"}]'; 3?>

index.html

html

1<!doctype html> 2<html lang="en"> 3<head> 4 <meta charset="utf-8"> 5 <title>jQuery UI Autocomplete - Remote datasource</title> 6 <link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> 7 <script src="//code.jquery.com/jquery-1.10.2.js"></script> 8 <script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script> 9 <script> 10 $(function() { 11 function log( message ) { 12 $( "<div>" ).text( message ).prependTo( "#log" ); 13 $( "#log" ).scrollTop( 0 ); 14 } 15 16 $( "#birds" ).autocomplete({ 17 source: "json_echo.php", 18 minLength: 2, 19 select: function( event, ui ) { 20 log( ui.item ? 21 "Selected: " + ui.item.value + " aka " + ui.item.id : 22 "Nothing selected, input was " + this.value ); 23 } 24 }); 25 }); 26 </script> 27 </head> 28<body> 29 30<div class="ui-widget"> 31 <label for="birds">Birds: </label> 32 <input id="birds"> 33</div> 34 35<div class="ui-widget" style="margin-top:2em; font-family:Arial"> 36 Result: 37 <div id="log" style="height: 200px; width: 300px; overflow: auto;" class="ui-widget-content"></div> 38</div> 39 40 41</body> 42</html>

index.htmlを開きテキストボックスに入力してみたところ、item13が候補として表示されることを確認しました。
この場合はどんな文字列を入力しても、echoで返されるJSONデータは決まっているので常にitem1
3が表示されるということで、正しい動作だと思います。

この結果を受けてCakePHPで以下のように実装しました。
TableAController.php

php

1 public function autocomplete(){ 2 echo '[{"id":"1","value":"item1"},{"id":"2","value":"item2"},{"id":"3","value":"item3"}]'; 3 } 4

TableA/index.ctp

html

1 <script> 2 $(function() { 3 function log( message ) { 4 $( "<div>" ).text( message ).prependTo( "#log" ); 5 $( "#log" ).scrollTop( 0 ); 6 } 7 8 $( "#birds" ).autocomplete({ 9 source: '<?php echo $this->Html->url(array('controller' => 'OrderLedgers', 'action' => 'autocomplete')); ?>', 10 minLength: 2, 11 select: function( event, ui ) { 12 log( ui.item ? 13 "Selected: " + ui.item.value + " aka " + ui.item.id : 14 "Nothing selected, input was " + this.value ); 15 } 16 }); 17 }); 18 </script> 19 20HTML部分は同一

これを実行してみましたが、動作せず。。。

そしてたった今、Chromeのブラウザコンソールに**500 (Internal Server Error)**が表示されていることに気付きました。
(途中でeripongさん、tozjpさんが言っていたのはこういう所を見ろということだったんですね・・・)
少し前進した気がしますので、もう少し調べてみたいと思います。


解決しました!

根本的な原因は、tozjpさんのご指摘の通り、autocompleteメソッドからのレスポンスが純粋なJSONではなかったことでした。
CakePHPがビューなどを自動で付与したデータを返していたため、javascript側で正常に処理できなかったのだと思われます。

http://digape.com/201210/cakephp2-json%E5%BD%A2%E5%BC%8F%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E6%89%8B%E8%BB%BD%E3%81%AB%E5%87%BA%E5%8A%9B%E3%81%99%E3%82%8B/
http://www.sssg.org/blogs/hiro345/archives/14793.html
上記のリンクを参考に、JSONのみを返すアクションに修正しました。
まずは予め用意した配列を返せるか検証。
TableAController.php

php

1 public function autocomplete(){ 2 $result = array( 3 ['id' => '1', 'value' => 'item1'], 4 ['id' => '2', 'value' => 'item2'], 5 ['id' => '3', 'value' => 'item3'], 6 ); 7 $this->viewClass = 'Json'; 8 $this->set(compact('result')); 9 $this->set('_serialize', 'result'); 10 }

autocompleteアクションを単体で実行し、JSONのみが表示されることを確認しました。
テキストボックスに入力してみると、item1~3の候補がドロップダウンされることも確認。

続いて元々やりたかった別テーブルからのデータを取得するように修正。
TableAController.php

php

1public function autocomplete(){ 2 $this->loadModel('TableB'); 3 $field = 'name'; 4 $term = $this->params['url']['term']; 5 6 // 入力値 無:全てのデータの中から10件返す。 7 // 入力値 有:入力値を含むデータを10件返す 8 $condition = array(); 9 if(!empty($term)){ 10 $condition = array('TableB.'.$field.' like' => "%".$term."%"); 11 } 12 13 $query = array( 14 'fields' => array($field), 15 'conditions' => $condition, 16 'limit' => 10, 17 'order' => array('TableB.'.$field => 'ASC'), 18 'group' => $field, 19 ); 20 21 $data = array(); 22 $items = $this->TableB->find('all', $query); 23 24 foreach ($items as $item) { 25 $cnt = array_push($data, $item['TableB'][$field]); 26 } 27 28 // JSONデータのみを返す 29 $this->viewClass = 'Json'; 30 $this->set(compact('data')); 31 $this->set('_serialize', 'data'); 32}

ビュー側はこうです。
TableA/index.ctp

php

1<script type="text/javascript"> 2$(function(){ 3 $('#autocomplete').autocomplete({ 4 source: '<?php echo $this->Html->url(array('controller' => 'TableA', 'action' => 'autocomplete')); ?>', 5 autoFocus: true, 6 delay: 500, 7 minLength: 2 8 }); 9}) 10</script> 11 12<?php echo $this->Form->input('name', array( 13 'type' => 'text', 14 'id' => 'autocomplete', 15)); ?>

これにより、ちゃんとテーブルBのデータがオートコンプリート表示されるようになりました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

java / jsp ですが、試しました。
https://jqueryui.com/autocomplete/#remote
このページの View Source リンクからサンプルを全コピー。
source プロパティだけちょろっと変更。
NewFile.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> [ {"id" : "id01", "value" : "United State of America" }, {"id" : "id02", "value" : "Hawaii America" }, {"id" : "id03", "value" : "Alaska America" }, {"id" : "id04", "value" : "South America" }, {"id" : "id05", "value" : "North America" } ] コード

index.html

<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>jQuery UI Autocomplete - Remote datasource</title> <link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="//code.jquery.com/jquery-1.10.2.js"></script> <script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script> <link rel="stylesheet" href="/resources/demos/style.css"> <style> .ui-autocomplete-loading { background: white url("images/ui-anim_basic_16x16.gif") right center no-repeat; } </style> <script> $(function() { function log( message ) { $( "<div>" ).text( message ).prependTo( "#log" ); $( "#log" ).scrollTop( 0 ); } $( "#birds" ).autocomplete({ source: "NewFile.jsp", minLength: 2, select: function( event, ui ) { log( ui.item ? "Selected: " + ui.item.value + " aka " + ui.item.id : "Nothing selected, input was " + this.value ); } }); }); </script> </head> <body> <div class="ui-widget"> <label for="birds">Birds: </label> <input id="birds"> </div> <div class="ui-widget" style="margin-top:2em; font-family:Arial"> Result: <div id="log" style="height: 200px; width: 300px; overflow: auto;" class="ui-widget-content"></div> </div> </body> </html> コード

これで期待する結果が得られましたよ。

なので、php のメソッドautocomplete が返却する json が NewFile.jsp の書式と同じであるか
どうか確認してください。

投稿2015/10/28 16:07

ipadcaron

総合スコア1693

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ipadcaron

2015/10/28 16:24

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> [ <%-- // この書き方はうまく動く {"id" : "id01", "value" : "United State of America" }, {"id" : "id02", "value" : "Hawaii America" }, {"id" : "id03", "value" : "Alaska America" }, {"id" : "id04", "value" : "South America" }, {"id" : "id05", "value" : "North America" } --%> <%-- // この書き方もうまく動作する一覧は、value の値が並び順で表示される { "name" : "OK1n", "value" : "OK1v", "id": "id11" }, { "name" : "OK2n", "value" : "OK2v", "id": "id12" }, { "name" : "OK3n", "value" : "OK3v", "id": "id13" }, { "name" : "OK4n", "value" : "OK4v", "id": "id14" } --%> <%-- //要素がマップではない場合でもOK。 "value1", "value2", "value3", "value4" --%> ] value がない場合は単純に配列でOKみたいですね。 <%-- --> はJSPコメント、3つの中身をコピペして確認してみてください。 まずは、autocomplete メソッド(PHP)の、中身を、 echo だけのシンプルなものでうまく動く事を確認してから、DBアクセスなりを 実装すると手戻りが少なくて済みそうですね。
ipadcaron

2015/10/28 16:36

[{"id" : "xxx" , "value" : "valueed"} , ... ] 形式ではないJSONデータの場合は、_renderItem(ui, item) コールバックを実装することで 解決できるみたいですね。表示名と選択された時の値を設定した <li /> を自前で作成し、ui.appendToするそうです。 ココ http://api.jqueryui.com/autocomplete/#method-_renderItem >このURLにアクセスすると、テーブルBからnameフィールドに"hoge"が含まれるレコードがJSON形式で返ってくることが確認できています。 このくだりを見落としていました。"name" は autocomplete 内処理では、見てないみたいです。
guest

0

ベストアンサー

'/TableA/autocomplete'

http://localhost/TableA/autocomplete
と解決されます。(cakephp/が足りません。)

cakephp/を書いてしまえば解決なのですが、そもそも CakePHP では URL を直に書くことはせず、Helper を使用して生成しましょう。
あとから URL が変更になっても柔軟に対応できます。
http://book.cakephp.org/2.0/ja/core-libraries/helpers/html.html#HtmlHelper::url

php

1<script type="text/javascript"> 2$(function(){ 3 $('#autocomplete').autocomplete({ 4 source: <?=json_encode($this->Html->url(["controller" => "TableA", "action" => "autocomplete"]))?>, 5 // ・・・ 6 }); 7}) 8</script>

先の方のご回答にある source プロパティの形式は確かに気になるところですが、貼っていただいた解説サイトのサンプル一つで URL が指定されているようなので大丈夫ということでしょうか。プラグイン自体をこちらでは試していませんので、そこはちょっと気をつけて確認してみてください。

投稿2015/10/28 06:29

編集2015/10/28 06:32
tozjp

総合スコア790

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tozjp

2015/10/28 06:35

あ、やっぱりこれではダメですね。 入力途中の文字列をパラメータに渡す必要があるので、`?term=hoge`の部分はその都度取り直さなければいけません。やはりコールバック関数で URL の後半部分を毎回付け直す必要があると思います。
ipadcaron

2015/10/28 06:55

そこらへんは、autocomplete が面倒見てくれるようですが、source にstring指定すると、url と見なす、まではいいのですが、そのurl へのアクセスがget になるんじゃないかと。翻訳サイトのびみょうな翻訳結果から推測するに。スクリプトのは、http method 指定する記述が有りませんから。
seagal18

2015/10/28 08:01

入力文字列を取得してURLに付け足す処理は、autocompleteがやってくれると思っています。 http://api.jqueryui.com/autocomplete/#option-source (上記ページのMultiple types supported:のStringの部分) 現状ではURLの渡し方が悪いということでしょうか。 教えていただいたCakePHPのurl()メソッドを使ってみようと思いますが、GET、POST等の指定をどのようにするかまだ分かっていませんので、引き続き検証してみます。
seagal18

2015/10/28 08:18

ありがとうございます。GETでいいというのは分かるのですが、 CakePHPのurl()メソッドでGET送信するにはどうやって書けばいいんだろう、という意味合いでした。 とはいえGETについて勘違いしていたところがあり、autocompleteで"?term=hoge"の部分を付け足してくれるというなら、そのままでいいはずですよね・・・
eripong

2015/10/28 08:30

CakePHPのurlメソッドは、文字列を返すだけなので、 それを使ってGETするかPOSTするかはjavascriptの実装任せです。 この場合autocompleteでGETしてくれるので問題ないと思います。 ただ、tozjpさんのコードにあるjson_encodeは不要な気がします。
seagal18

2015/10/28 08:36

sourceプロパティを以下のようにしてみましたが、ダメでした。   source: '<?php echo $this->Html->url(array('controller' => 'TableA', 'action' => 'autocomplete')); ?>', PHP部分だけ出力すると、以下のURLになります。   /cakephp/TableA/autocomplete なのでGETで送信されるURLとしては   http://localhost/cakephp/TableA/autocomplete?term=hoge となっているはずなのですが・・・本日は時間が失くなってしまったためまた明日検証してみたいと思います。
eripong

2015/10/28 08:39

ブラウザで、どういうリクエストが送信されているか確認した方が良さそうですね。
tozjp

2015/10/28 10:48

> 入力文字列を取得してURLに付け足す処理は、autocompleteがやってくれると思っています。 あ、 term というキーは ライブラリがデフォルトで使用しているものだったんですね。 すみません、それならパラメーターのない URL だけで問題なさそうですね。 > eripong さん json_encode については、目的はほぼURL文字列を "" で括るためにつけています。 とは言えURLの場合にかぎらず、 JavaScript に値を渡す場合には絶対にエスケープが必要な文字列が評価される心配がないか調べるよりも時間も正確さも優っていておすすめです。 脱線しましたが、現在の情報では僕にははっきりとした問題点は見当たりません。 どこか質問文にない箇所に問題があるのではないかと思っているのですが、例えば関連ライブラリは正常に読み込まれているのでしょうか。 ブラウザのコンソールにエラーは出力されていませんか。 一旦 Ajax と切り離して、 source: に生の配列値を指定したら動くのでしょうか。
eripong

2015/10/28 11:11

> tozjpさん json_encodeについて、了解です。 そういうことだったんですね。
seagal18

2015/10/29 05:14

>tozjpさん >一旦 Ajax と切り離して、 source: に生の配列値を指定したら動くのでしょうか。 https://jqueryui.com/autocomplete/#default 上記サンプルの<script>内のコードをそのまま使ってみたところ動作したので、jquery自体の読み込みは問題なさそうです。
eripong

2015/10/29 05:32

どのブラウザを使用されているか分かりませんが、 https://app.codegrid.net/entry/ajax-1 のような方法で、リクエスト、レスポンスの内容を確認されてはいかがでしょうか?
seagal18

2015/10/29 06:28

ChromeのDeveloper Toolsで確認したところ、500 Internal Server Errorが発生していました。 ここでリクエストなどが確認できるということを初めて知りました。。。(今までHTMLのソースを見ることにしか使っていませんでした) エラー解消方法について調べてみます。
tozjp

2015/10/29 06:36

CakePHPを離れて久しいので記憶が曖昧なのですが、 > http://localhost/cakephp/TableA/autocomplete?term=hoge > このURLにアクセスすると、テーブルBからnameフィールドに"hoge"が含まれるレコードがJSON形式で返ってくることが確認できています。 これってちゃんと JSON "のみ" が返ってきていますか? つまり、表示された JSON から、ブラウザのソースコードを見る機能で確認して、純粋な JSON ファイルと同じテキストデータになっていますか? アクションメソッド内でビューを無効化している様子がないのですが、これってどこか他の場所で無効化できるんでしたっけ? アクションメソッド内で文字列を直接 echo しちゃうのは、Cake 的にはマナー違反かと思います。 JSON ビューという特別なビューが用意されているので、それを使ったほうが良さそうです。 http://book.cakephp.org/2.0/ja/views/json-and-xml-views.html
eripong

2015/10/29 06:45

> tozjpさん そうなんですね。その確認も必要そうです。 ただ、今は500エラーなのでそもそも応答が返せていないのでは? と思いリクエストの比較を提案しました。
seagal18

2015/10/29 08:35

無事、解決することができました。 皆さんの意見はどれも参考にさせて頂きましたが、CakePHPということを重点的に考慮して下さったtozjpさんの回答をベストアンサーとさせていただきます。 最初に回答いただいたipadcaronさん、eripongさんもありがとうございました!
guest

0

http://www.buildinsider.net/web/jqueryuiref/0017
ここみると、source プロパティは、URL ではなくて、結果の配列を指定するようでづね。
ちょっと探してみたら、コールバックめそっどが指定できるようです。

https://jqueryui.com/autocomplete/#remote-jsonp
このページの remote jsonp data source ボタンクリックして、view source リンクを選択。
やりたいことがまんま書いてあるので適当ににコピペしてやってみてください。

投稿2015/10/28 05:32

ipadcaron

総合スコア1693

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ipadcaron

2015/10/28 07:39

http://book.cakephp.org/2.0/ja/core-libraries/helpers/form.html formhelper がちょっと難しいのでづが、画面のソースをみて、input タグの name に指定されている文字列が、 <?php echo $this->Form->input('name', array( 'type' => 'text', 'id' => 'autocomplete', )); ?> このタグが展開されたもので、 パラメーターとして受け取るには、 public function autocomplete(){ $this->loadModel('TableB'); $field = 'name'; $term = $this->params['url']['term']; この$term の右辺に name の記述があってないと受け取れないのでは、と思います。 term は、php の autocomplete メソッド内にのみ登場し、html にはどこにも term が見当たりません。
seagal18

2015/10/28 07:54

回答有り難うございます。 http://api.jqueryui.com/autocomplete/#option-source こちらのドキュメントのMultiple types supported:のStringの項を見ると、入力したテキストはURLの末尾に?term=~~~という形でくっついて送信される、と書いてあるように思われます。 なのでautocomplete側ではtermが来るという前提で処理を書けばいいと判断しました。 引き続き検証してみます。
ipadcaron

2015/10/28 15:16

とりあえず、source:function の書き方で動くことを確認しませんか。 source:url に拘るならば、 http://jqueryui.com/autocomplete/#remote このページに、source に url を指定した記述があります。 このサンプルでは、選択結果の取得に、autocomplete#select プロパティのコールバックで処理しています。 ドロップ一覧の JSON 配列は、以下の形式を想定しているようですが、サーバー処理の返す結果は相違ありませんか? [ { "id" : "任意の固有名称" , "value" : "任意の固有名称の値" } , { 以下、続く。 ようするに、サーバー処理は、JSON形式で、 一次配列を返す。 配列要素は、id と value をキーに持つマップである。 となります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問