ExtJS入門その11『Ext.data.Store』
2009/09/15 09:54:26
「Ext.data.Store」は色々な書き方ができるのでほんまややこしい。
何がややこしいというか混乱させているのは、よくあるサンプルの書き方がシンプルさを追求してか、
短い書き方、省略した書き方で書かれているからだと思う。
それもいいのだけれども、この書き方はこんな書き方もできる!こう書いてもおんなじだよ!という紹介の仕方はあまり見ない。
それがあれば学習効率も上がるのだけれども、仕方ないから自分で泥臭く手を動かして確かめるしかないのよね。
何がややこしいというか混乱させているのは、よくあるサンプルの書き方がシンプルさを追求してか、
短い書き方、省略した書き方で書かれているからだと思う。
それもいいのだけれども、この書き方はこんな書き方もできる!こう書いてもおんなじだよ!という紹介の仕方はあまり見ない。
それがあれば学習効率も上がるのだけれども、仕方ないから自分で泥臭く手を動かして確かめるしかないのよね。
まずよくある形から。
「reader: 」のところだけれども構造が
APIドキュメントを読んでも何故このような書き方ができるのかはいまだにわからないのですが、これは
第2パラメーターで指定した「[]」は実は「Ext.data.Record.create」の省略である(多分)。
で、こう書けるのなら
また
第2パラメーターをなくして「fields: 」に指定する形。
ここまでは「reader: 」。
次に「proxy: 」だが、勘違いというか思い込みで結構ハマるというか…私はハマりました。
結論から言うと別ドメイン(いわゆるクロスドメイン)にあるデータはどうやってもとれません。(※間違ってました。下に追記してます)
「Ext.data.HttpProxyはHTTP経由でデータを取得する際に利用」とあるのでてっきり「http://〜」で指定できるのかと思いこんでました。
違うんですね。
この形では「Ext.data.HttpProxy」だろうが「Ext.data.ScriptTagProxy」だろうが、同サーバでの話しなのです。
「HTTP経由で」っていうのは、例えばデータ取得ファイルがPHPファイルで動的にXMLデータを返すものだとしたらこのデータを取ろうとするなら、必ず「HTTP経由で」しなければならないでしょう?
ただし「HTTP経由で」開いても直に開いてもそのままのXMLファイルという場合はどっちでもいいわけです。
先のPHPファイルを直に参照したらただのスクリプトですからね。
だから「HTTP経由で」ある必要があるというわけ。
上記の「proxy: 」のところで「Ext.data.HttpProxy」を通して「data.json」にアクセスしてますが、そんな必要はなく
普通に考えたらそりゃそうですよね…orz
必死に別ドメインにJSONファイル置いてFireBugで「Access to restricted URI denied code: 1012」が出て、なんでやろな〜?と悩んでた自分が恥ずかしい…orz
あと、メソッド「load()」を使って後からデータを実際に取得しているわけですが、すぐ使う場合とかはいちいち外でメソッド呼び出しもあれなので、
メソッド「setDefaultSort('name','ASC')」でマッピングした「name」を「昇順」で設定できるのも、
中のコンフィグオプション「sortInfo: 」で「{ field:"name", direction:'ASC' }」とすることができるのも覚えておきましょう。
※2009/09/16追記
上記で「「proxy: 」では別ドメイン(いわゆるクロスドメイン)にあるデータはどうやってもとれません」と豪語しましたが、ごめんなさいm(_ _)m間違えておりましたorz
勘違いの勘違いでしたのでしきり直しというか、非常に面倒な作業ですがひとつひとつ確認していきます。(やっぱり泥臭いことをやらずにわかったつもりで結論付けてはいけませんね。やりたくないから決め付けてしまうのです反省orz)
ちなみにここで使うJSONファイルの内容はこんな感じ。
data.json
XMLファイルの内容はこんな感じ。
data.xml
ファイルのエンコードはUTF-8で保存して下さい。
「同サーバにある生ファイルの取得」するには「Ext.data.HttpProxy」を使います。
XMLでもJSONファイルでも同じです。ちなみにこの違いが出るのは「reader: 」のところですので一応そこも要注意です。
APIドキュメントによると「Ext.data.HttpProxy」は
ではやってみましょう。
■同サーバにある生JSONファイルの取得 [デモ]
■同サーバにある生XMLファイルの取得 [デモ]
この際ですので「ちなみに」というところもおさえておきましょう。
JSONファイル
XMLファイル
■別サーバにある生JSONファイルの取得 [デモ]
さきほど「Ext.data.HttpProxy」は同ドメインしか使えません。クロスドメインの場合は「Ext.data.ScriptTagProxy」を使用しなさいとあったので素直にやってみたら取れません。
Firebugのコンソールには「invalid label」というエラーが出ているので何かが悪いのでしょう。
これで単純に内部の場合は「Ext.data.HttpProxy」にして外部の場合は「Ext.data.ScriptTagProxy」を使うという図式は崩れ去りました。
そんな単純じゃねぇぞ(#゜Д゜)ゴルァ!のようです。厄介ですね…
で、色々やりながらどうしたものか…?と思っていてサンプルを見ていたらあることに気がついてやってみたところ取れました…
やり方はというと、JSONデータ全体を「stcCallback1001()」でくくってやるといいようです。
つまり
取れるには取れたのですが、このやり方がはたして正しいやり方なのか…?
唯一見つけたはっきりそう書かれている記事は
ComboBox with remote JSON data(Learning ExtJS 2008/07/03)
だけ。
記事によると
今のところちょっと(゚_。)?なのですが、あまりつまっていては先に進めませんので、ではXMLの場合はどうなのでしょうか?
■別サーバにある生XMLファイルの取得 [デモ]
あるブログで「Ext.data.ScriptTagProxy」はJSONP形式のデータを取得する時に使うよ〜とも書かれていたので恐らく、多分、別サーバの生XMLファイルはこの形ではとれないのでしょう、きっと。
で前々からこのJSONP形式って何じゃろかいなとは思っていたのだが、まぁJSONのようなものやろと高を括っていたんだけれども、ここで改めてちゃんと調べて見るとさっきの「stcCallback1001」の解答が出ちゃいましたよ。
JSONP(JSON with Padding)とはJSONのデータを括弧でくくって任意の関数を作りその関数をコールバック関数で使えるようにしたものであるらしいという言葉にするとかなりわかりにくいものだが、ちょっと調べるとなるほどなぁというものだ。
さきほどのはJSONデータを「stcCallback1001()」の中に押し込めて、こいつを取得した瞬間にstcCallback1001()関数が使えるようになるというわけである。引数にはJSONのデータが丸々入っているので簡単にアクセスできるし簡単にデータを扱えるというわけ。
簡単なテストをしてみることにする。
■JSONPのテスト [デモ]
さて正体がわかったことにはわかったのだが、コールバック関数として「stcCallback1001」は固定なのかはまだ今のところはわからない。(多分こういった生JSONファイルの場合は無理だろうが、動的なスクリプトならコールバック関数文字列を送ってやってそれを使えば制御できそうだなぁ〜、あぁあった「callbackParam」らしきコンフィグオプションがあるのでここで指定するのかな?)
■別サーバにあるJSONP形式を吐き出すPHPスクリプトから取得 [デモ]
json.php
生のJSONファイルとの違いはないです。ただechoで同じ文字列を吐き出しているだけ。
APIドキュメントによると、JSONPなら「text/javascript」、ただのJSONなら「application/x-json」というJAVAスクリプト例を提示しています。
でもやってみたところ、JSONP、JSONともにどちらの「Content-Type」でも表示されるようです。
ではさっきの「callbackParam」を検証してみましょう。
試しに
json2.php
すると接続で「http://〜&callback=stcCallback1001」となっているところが「http://〜&hoge=stcCallback1001」となりました。
[デモ]
はは〜見えてきましたね〜。
「callbackParam: 」はデフォルトでは「callback」らしいですが、ここの値を変更することによってコールバック関数文字列をセットする変数を制御できるということなんですな。
なので「$_REQUEST['hoge']」でコールバック関数をセットすれば「stcCallback1001」を全く知らなくてもいいというわけ。(なんだかなーとは思うけど…)
どうやらここでのコールバック関数は「stcCallback1001」で固定らしいですね。(※m(_ _)m大ウソです。この記事を参照ください)
■同サーバにあるJSON形式を吐き出すPHPスクリプトから取得 [デモ]
json.php
この場合は「stcCallback1001()」コールバック関数でくくってはいけません。
ただし「Ext.data.ScriptTagProxy」の場合はくくる必要があります。ちょっとややこしいかもしれませんが、混乱しないように整理して把握しておかないと、取得できん!と取り乱すことになりかねません。
■同サーバにあるXML形式を吐き出すPHPスクリプトから取得 [デモ]
XMLHttpRequest接続でデータは取得できているみたいなのですが、レンダリングされないですね。どこが悪いんだろう…
色々やっていたら表示されました。「Content-Type:text/xml」として吐き出さなければならないみたいです。あぁAPIドキュメントにもきっちり書かれていますねorz
「Content-Type:text/html」としてました。。。(JSONの方ではそれでいけてたので、というかここらへんちゃんとわかってねぇなぁorz)
xml.php
ちなみに補足だが、データの種類、取得方法によっていくつかの「Ext.data.〜」組み合わせパターンができると思う。
あるパターンの組み合わせをひとつにしたクラスが予め用意されてあるものもあるので一応見ておきましょう。
「Ext.data.JsonStore」=「Ext.data.Store」+「Ext.data.HttpProxy」+「Ext.data.JsonReader」 [デモ]
「Ext.data.XmlStore」=「Ext.data.Store」+「Ext.data.HttpProxy」+「Ext.data.XmlReader」 [デモ]
どちらもかなり簡潔にかけるのでソースが短くなってよいが、今でこそなるほどとわかるからいいものの最初これから入ったら絶対訳わかんなくなるに違いない。
とまぁこんな感じですねぇ。
長い!疲れた(;´ρ`)
var MyDataStore = new Ext.data.Store({
proxy: new Ext.data.HttpProxy({
url: './data.json',
method: 'GET'
}),
reader: new Ext.data.JsonReader({
root: 'humandata'
},[
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
])
});
MyDataStore.load();「reader: 」のところだけれども構造が
new Ext.data.JsonReader({
コンフィグオプション
},第2パラメーターとして読み込むXMLタグ名)となっている。APIドキュメントを読んでも何故このような書き方ができるのかはいまだにわからないのですが、これは
var MyDataStore = new Ext.data.Store({
proxy: new Ext.data.HttpProxy({
url: './data.json',
method: 'GET'
}),
reader: new Ext.data.JsonReader({
root: 'humandata'
},
Ext.data.Record.create([
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]))
});
MyDataStore.load();のようにも書ける。第2パラメーターで指定した「[]」は実は「Ext.data.Record.create」の省略である(多分)。
で、こう書けるのなら
var MyDataRecord = Ext.data.Record.create([
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]);
var MyDataStore = new Ext.data.Store({
proxy: new Ext.data.HttpProxy({
url: './data.json',
method: 'GET'
}),
reader: new Ext.data.JsonReader({
root: 'humandata'
},MyDataRecord)
});
MyDataStore.load();のように一旦変数に置いておいて代入する形をとれる。また
var MyDataStore = new Ext.data.Store({
proxy: new Ext.data.HttpProxy({
url: './data.json',
method: 'GET'
}),
reader: new Ext.data.JsonReader({
root: 'humandata',
fields: [
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]
})
});
MyDataStore.load();のようにも書ける。第2パラメーターをなくして「fields: 」に指定する形。
ここまでは「reader: 」。
次に「proxy: 」だが、勘違いというか思い込みで結構ハマるというか…私はハマりました。
結論から言うと別ドメイン(いわゆるクロスドメイン)にあるデータはどうやってもとれません。(※間違ってました。下に追記してます)
「Ext.data.HttpProxyはHTTP経由でデータを取得する際に利用」とあるのでてっきり「http://〜」で指定できるのかと思いこんでました。
違うんですね。
この形では「Ext.data.HttpProxy」だろうが「Ext.data.ScriptTagProxy」だろうが、同サーバでの話しなのです。
「HTTP経由で」っていうのは、例えばデータ取得ファイルがPHPファイルで動的にXMLデータを返すものだとしたらこのデータを取ろうとするなら、必ず「HTTP経由で」しなければならないでしょう?
ただし「HTTP経由で」開いても直に開いてもそのままのXMLファイルという場合はどっちでもいいわけです。
先のPHPファイルを直に参照したらただのスクリプトですからね。
だから「HTTP経由で」ある必要があるというわけ。
上記の「proxy: 」のところで「Ext.data.HttpProxy」を通して「data.json」にアクセスしてますが、そんな必要はなく
var MyDataRecord = Ext.data.Record.create([
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]);
var MyDataStore = new Ext.data.Store({
url: './data.json',
reader: new Ext.data.JsonReader({
root: 'humandata'
},MyDataRecord)
});
MyDataStore.load();でもいいわけです。普通に考えたらそりゃそうですよね…orz
必死に別ドメインにJSONファイル置いてFireBugで「Access to restricted URI denied code: 1012」が出て、なんでやろな〜?と悩んでた自分が恥ずかしい…orz
あと、メソッド「load()」を使って後からデータを実際に取得しているわけですが、すぐ使う場合とかはいちいち外でメソッド呼び出しもあれなので、
var MyDataRecord = Ext.data.Record.create([
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]);
var MyDataStore = new Ext.data.Store({
proxy: new Ext.data.HttpProxy({
url: './data.json',
method: 'GET'
}),
reader: new Ext.data.JsonReader({
root: 'data'
},MyDataRecord),
autoLoad: true
});というように中のコンフィグオプション「autoLoad: 」で自動でメソッド「load()」をかけることができるらしい。メソッド「setDefaultSort('name','ASC')」でマッピングした「name」を「昇順」で設定できるのも、
中のコンフィグオプション「sortInfo: 」で「{ field:"name", direction:'ASC' }」とすることができるのも覚えておきましょう。
※2009/09/16追記
上記で「「proxy: 」では別ドメイン(いわゆるクロスドメイン)にあるデータはどうやってもとれません」と豪語しましたが、ごめんなさいm(_ _)m間違えておりましたorz
勘違いの勘違いでしたのでしきり直しというか、非常に面倒な作業ですがひとつひとつ確認していきます。(やっぱり泥臭いことをやらずにわかったつもりで結論付けてはいけませんね。やりたくないから決め付けてしまうのです反省orz)
ちなみにここで使うJSONファイルの内容はこんな感じ。
data.json
{ "totalCount":"17","humandata": [
{
"name": "佐藤",
"gender": "男",
"tel": "090-8580-4820",
"mail": "wxqm@viutqz.com",
"info": "リラックスべたで、怠けることを知らない。"
},
{
"name": "鈴木",
"gender": "男",
"tel": "090-8407-7990",
"mail": "mlcs@cyppsi.com",
"info": "正しいことは、唯一つだと思っている。"
},
{
"name": "高橋",
"gender": "女",
"tel": "090-7749-4837",
"mail": "xvrf@ozmzwj.com",
"info": "いつも公平であるかどうか気にかける。"
},
{
"name": "田中",
"gender": "男",
"tel": "090-1500-0781",
"mail": "rhqt@devgce.com",
"info": "さびしがり屋で、家族と行動をともにしたがる。"
},
{
"name": "渡辺",
"gender": "女",
"tel": "090-0643-1860",
"mail": "xhiw@hbaanj.com",
"info": "仕事のミスはほんの少しでも気にする。"
},
{
"name": "伊藤",
"gender": "男",
"tel": "090-6000-9422",
"mail": "ctcf@iylilz.com",
"info": "義理硬いが、人づきあいを避ける。"
},
{
"name": "山本",
"gender": "女",
"tel": "090-2739-6835",
"mail": "cakc@owivmj.com",
"info": "シャイで人見知り。"
},
{
"name": "中村",
"gender": "男",
"tel": "090-9009-5068",
"mail": "uvei@bypdib.com",
"info": "柔軟な考え方や生き方がしにくい。"
},
{
"name": "小林",
"gender": "男",
"tel": "090-2454-0886",
"mail": "mxlg@qzdenx.com",
"info": "いつも緊張して、体や関節がこわばっている。"
},
{
"name": "加藤",
"gender": "男",
"tel": "090-1704-6387",
"mail": "hlpd@gulpta.com",
"info": "優等生気質で、決まりを守るのは当たり前と考える。"
},
{
"name": "吉田",
"gender": "男",
"tel": "090-9682-4887",
"mail": "hnch@evcmuq.com",
"info": "言葉使いがしっかりと、ていねいであることが多い。"
},
{
"name": "山田",
"gender": "女",
"tel": "090-5429-8868",
"mail": "xouy@pclzhz.com",
"info": "ナチュラリストで、スポーツを愛好することが多い。"
},
{
"name": "佐々木",
"gender": "女",
"tel": "090-4249-0096",
"mail": "prqg@hhnsfe.com",
"info": "何事もねばならない、すべきであると考えがち。"
},
{
"name": "斎藤",
"gender": "男",
"tel": "090-4454-8984",
"mail": "tole@bwluxz.com",
"info": "努力家・勤勉家。"
},
{
"name": "山口",
"gender": "女",
"tel": "090-6533-0520",
"mail": "awro@oagsbb.com",
"info": "人目を気にして、恥意識がかなり強い。"
},
{
"name": "松本",
"gender": "女",
"tel": "090-6997-9366",
"mail": "uubz@mzrfvd.com",
"info": "性急で待てない気分になり、イライラしやすい。"
},
{
"name": "井上",
"gender": "男",
"tel": "090-8942-1284",
"mail": "ihbv@wwmirx.com",
"info": "狭量だが、言うことに裏表がない。"
}
]}XMLファイルの内容はこんな感じ。
data.xml
<?xml version="1.0" encoding="UTF-8" ?> <list> <init> <totalCount>17</totalCount> </init> <humandata> <name>佐藤</name> <gender>男</gender> <tel>090-8580-4820</tel> <mail>wxqm@viutqz.com</mail> <info>リラックスべたで、怠けることを知らない。</info> </humandata> <humandata> <name>鈴木</name> <gender>男</gender> <tel>090-8407-7990</tel> <mail>mlcs@cyppsi.com</mail> <info>正しいことは、唯一つだと思っている。</info> </humandata> <humandata> <name>高橋</name> <gender>女</gender> <tel>090-7749-4837</tel> <mail>xvrf@ozmzwj.com</mail> <info>いつも公平であるかどうか気にかける。</info> </humandata> <humandata> <name>田中</name> <gender>男</gender> <tel>090-1500-0781</tel> <mail>rhqt@devgce.com</mail> <info>さびしがり屋で、家族と行動をともにしたがる。</info> </humandata> <humandata> <name>渡辺</name> <gender>女</gender> <tel>090-0643-1860</tel> <mail>xhiw@hbaanj.com</mail> <info>仕事のミスはほんの少しでも気にする。</info> </humandata> <humandata> <name>伊藤</name> <gender>男</gender> <tel>090-6000-9422</tel> <mail>ctcf@iylilz.com</mail> <info>義理硬いが、人づきあいを避ける。</info> </humandata> <humandata> <name>山本</name> <gender>女</gender> <tel>090-2739-6835</tel> <mail>cakc@owivmj.com</mail> <info>シャイで人見知り。</info> </humandata> <humandata> <name>中村</name> <gender>男</gender> <tel>090-9009-5068</tel> <mail>uvei@bypdib.com</mail> <info>柔軟な考え方や生き方がしにくい。</info> </humandata> <humandata> <name>小林</name> <gender>男</gender> <tel>090-2454-0886</tel> <mail>mxlg@qzdenx.com</mail> <info>いつも緊張して、体や関節がこわばっている。</info> </humandata> <humandata> <name>加藤</name> <gender>男</gender> <tel>090-1704-6387</tel> <mail>hlpd@gulpta.com</mail> <info>優等生気質で、決まりを守るのは当たり前と考える。</info> </humandata> <humandata> <name>吉田</name> <gender>男</gender> <tel>090-9682-4887</tel> <mail>hnch@evcmuq.com</mail> <info>言葉使いがしっかりと、ていねいであることが多い。</info> </humandata> <humandata> <name>山田</name> <gender>女</gender> <tel>090-5429-8868</tel> <mail>xouy@pclzhz.com</mail> <info>ナチュラリストで、スポーツを愛好することが多い。</info> </humandata> <humandata> <name>佐々木</name> <gender>女</gender> <tel>090-4249-0096</tel> <mail>prqg@hhnsfe.com</mail> <info>何事もねばならない、すべきであると考えがち。</info> </humandata> <humandata> <name>斎藤</name> <gender>男</gender> <tel>090-4454-8984</tel> <mail>tole@bwluxz.com</mail> <info>努力家・勤勉家。</info> </humandata> <humandata> <name>山口</name> <gender>女</gender> <tel>090-6533-0520</tel> <mail>awro@oagsbb.com</mail> <info>人目を気にして、恥意識がかなり強い。</info> </humandata> <humandata> <name>松本</name> <gender>女</gender> <tel>090-6997-9366</tel> <mail>uubz@mzrfvd.com</mail> <info>性急で待てない気分になり、イライラしやすい。</info> </humandata> <humandata> <name>井上</name> <gender>男</gender> <tel>090-8942-1284</tel> <mail>ihbv@wwmirx.com</mail> <info>狭量だが、言うことに裏表がない。</info> </humandata> </list>いうまでもないですが、データ内容は全てでたらめです。
ファイルのエンコードはUTF-8で保存して下さい。
「同サーバにある生ファイルの取得」するには「Ext.data.HttpProxy」を使います。
XMLでもJSONファイルでも同じです。ちなみにこの違いが出るのは「reader: 」のところですので一応そこも要注意です。
APIドキュメントによると「Ext.data.HttpProxy」は
スクリプトが実行されるページと同じドメインで使うこと。 このクラスは別のドメイン(クロスドメイン)からのデータを取得するために使用することはできません。 クロスドメインのデータを取得する場合は「Ext.data.ScriptTagProxy」を使用してください。となっています。
ではやってみましょう。
■同サーバにある生JSONファイルの取得 [デモ]
var MyDataStore = new Ext.data.Store({
proxy: new Ext.data.HttpProxy({
url: './data.json'
}),
reader: new Ext.data.JsonReader({
root: 'humandata',
totalProperty: 'totalCount',
fields: [
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]
})
});
MyDataStore.load();問題なく取れました。FireFoxのFirebugのコンソールを見るとXMLHttpRequest接続で「GET http://〜data.json?_dc=*********** 200 OK ***ms」となっています。■同サーバにある生XMLファイルの取得 [デモ]
var MyDataStore = new Ext.data.Store({
proxy: new Ext.data.HttpProxy({
url: './data.xml'
}),
reader: new Ext.data.XmlReader({
record: 'humandata',
totalRecords: 'totalCount',
fields: [
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]
})
});
MyDataStore.load();問題なく取れました。FireFoxのFirebugのコンソールを見るとXMLHttpRequest接続で「GET http://〜data.xml?_dc=*********** 200 OK ***ms」となっています。この際ですので「ちなみに」というところもおさえておきましょう。
JSONファイル
new Ext.data.JsonReader({
root: 'ルートノード',
totalProperty: '全件数の意味を持つプロパティ名',
})XMLファイル
new Ext.data.XmlReader({
record: 'データを含む繰り返されるエレメントノードタグ名',
totalRecords: '全件数の意味を持つタグ名',
})となります。セットで覚えるしかないですね。■別サーバにある生JSONファイルの取得 [デモ]
var MyDataStore = new Ext.data.Store({
proxy: new Ext.data.ScriptTagProxy({
url: 'http://www.jinlingren.com/extjs/eid70/data.json'
}),
reader: new Ext.data.JsonReader({
root: 'humandata',
totalProperty: 'totalCount',
fields: [
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]
})
});
MyDataStore.load();取れません。さきほど「Ext.data.HttpProxy」は同ドメインしか使えません。クロスドメインの場合は「Ext.data.ScriptTagProxy」を使用しなさいとあったので素直にやってみたら取れません。
Firebugのコンソールには「invalid label」というエラーが出ているので何かが悪いのでしょう。
これで単純に内部の場合は「Ext.data.HttpProxy」にして外部の場合は「Ext.data.ScriptTagProxy」を使うという図式は崩れ去りました。
そんな単純じゃねぇぞ(#゜Д゜)ゴルァ!のようです。厄介ですね…
で、色々やりながらどうしたものか…?と思っていてサンプルを見ていたらあることに気がついてやってみたところ取れました…
やり方はというと、JSONデータ全体を「stcCallback1001()」でくくってやるといいようです。
つまり
stcCallback1001({
"totalCount":"17",
"humandata": [
{
"name": "佐藤",
"gender": "男",
"tel": "090-8580-4820",
"mail": "wxqm@viutqz.com",
"info": "リラックスべたで、怠けることを知らない。"
},
…省略
]
})のように。取れるには取れたのですが、このやり方がはたして正しいやり方なのか…?
唯一見つけたはっきりそう書かれている記事は
ComboBox with remote JSON data(Learning ExtJS 2008/07/03)
だけ。
記事によると
(Note that the JSON object is wrapped in the “stcCallback1001” function - this wrapping is required by the Ext “ScriptTagProxy”, which enables cross-site retrieval of data). JSONオブジェクトは「stcCallback1001」関数で括ることに注意ください (こうやってくくることは「Ext.data.ScriptTagProxy」では必要です) こうすることによってクロスドメインでのデータのやり取りができます。らしいのです。
今のところちょっと(゚_。)?なのですが、あまりつまっていては先に進めませんので、ではXMLの場合はどうなのでしょうか?
■別サーバにある生XMLファイルの取得 [デモ]
var MyDataStore = new Ext.data.Store({
proxy: new Ext.data.ScriptTagProxy({
url: 'http://www.jinlingren.com/extjs/eid70/data.xml'
}),
reader: new Ext.data.XmlReader({
record: 'humandata',
totalRecords: 'totalCount',
fields: [
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]
})
});
MyDataStore.load();取れません。あるブログで「Ext.data.ScriptTagProxy」はJSONP形式のデータを取得する時に使うよ〜とも書かれていたので恐らく、多分、別サーバの生XMLファイルはこの形ではとれないのでしょう、きっと。
で前々からこのJSONP形式って何じゃろかいなとは思っていたのだが、まぁJSONのようなものやろと高を括っていたんだけれども、ここで改めてちゃんと調べて見るとさっきの「stcCallback1001」の解答が出ちゃいましたよ。
JSONP(JSON with Padding)とはJSONのデータを括弧でくくって任意の関数を作りその関数をコールバック関数で使えるようにしたものであるらしいという言葉にするとかなりわかりにくいものだが、ちょっと調べるとなるほどなぁというものだ。
さきほどのはJSONデータを「stcCallback1001()」の中に押し込めて、こいつを取得した瞬間にstcCallback1001()関数が使えるようになるというわけである。引数にはJSONのデータが丸々入っているので簡単にアクセスできるし簡単にデータを扱えるというわけ。
簡単なテストをしてみることにする。
■JSONPのテスト [デモ]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>ExtJS入門サンプル</title>
<script type="text/javascript">
//<![CDATA[
function stcCallback1001(data){
alert(data.totalCount);
}
//]]>
</script>
</head>
<body>
<h1>JSONPのテスト</h1>
<script type="text/javascript" src="http://www.jinlingren.com/extjs/eid70/data.json"></script>
</body>
</html>「17」というアラートが出た。なるほどこうやってクロスドメインのJSONデータを取得して自分のところで自由に使えるわけですな。さて正体がわかったことにはわかったのだが、コールバック関数として「stcCallback1001」は固定なのかはまだ今のところはわからない。(多分こういった生JSONファイルの場合は無理だろうが、動的なスクリプトならコールバック関数文字列を送ってやってそれを使えば制御できそうだなぁ〜、あぁあった「callbackParam」らしきコンフィグオプションがあるのでここで指定するのかな?)
■別サーバにあるJSONP形式を吐き出すPHPスクリプトから取得 [デモ]
var MyDataStore = new Ext.data.Store({
proxy: new Ext.data.ScriptTagProxy({
url: 'http://www.jinlingren.com/extjs/eid70/json.php'
}),
reader: new Ext.data.JsonReader({
root: 'humandata',
totalProperty: 'totalCount',
fields: [
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]
})
});
MyDataStore.load();問題なく取れました。json.php
<?php
header("Content-Type:text/javascript; charset=UTF-8");
echo <<<E
stcCallback1001({
"totalCount":"17",
"humandata": [
{
"name": "佐藤",
"gender": "男",
"tel": "090-8580-4820",
"mail": "wxqm@viutqz.com",
"info": "リラックスべたで、怠けることを知らない。"
},
...省略
]
})
E;
?>「JSONP形式を吐き出すPHPスクリプト」はこんな感じ。生のJSONファイルとの違いはないです。ただechoで同じ文字列を吐き出しているだけ。
header("Content-Type:text/javascript; charset=UTF-8");としているけれどもheader("Content-Type:application/x-json; charset=UTF-8");でもOK。APIドキュメントによると、JSONPなら「text/javascript」、ただのJSONなら「application/x-json」というJAVAスクリプト例を提示しています。
でもやってみたところ、JSONP、JSONともにどちらの「Content-Type」でも表示されるようです。
ではさっきの「callbackParam」を検証してみましょう。
試しに
var MyDataStore = new Ext.data.Store({
proxy: new Ext.data.ScriptTagProxy({
url: 'http://www.jinlingren.com/extjs/eid70/json2.php',
callbackParam: 'hoge'
}),
reader: new Ext.data.JsonReader({
root: 'humandata',
totalProperty: 'totalCount',
fields: [
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]
})
});
MyDataStore.load();「callbackParam: 'hoge'」としてみました。json2.php
<?php
header("Content-Type:text/javascript; charset=UTF-8");
echo $_REQUEST['hoge']."(";
echo <<<E
{
"totalCount":"17",
"humandata": [
{
"name": "佐藤",
"gender": "男",
"tel": "090-8580-4820",
"mail": "wxqm@viutqz.com",
"info": "リラックスべたで、怠けることを知らない。"
},
...省略
]
})
E;
?>すると接続で「http://〜&callback=stcCallback1001」となっているところが「http://〜&hoge=stcCallback1001」となりました。
[デモ]
はは〜見えてきましたね〜。
「callbackParam: 」はデフォルトでは「callback」らしいですが、ここの値を変更することによってコールバック関数文字列をセットする変数を制御できるということなんですな。
なので「$_REQUEST['hoge']」でコールバック関数をセットすれば「stcCallback1001」を全く知らなくてもいいというわけ。(なんだかなーとは思うけど…)
どうやらここでのコールバック関数は「stcCallback1001」で固定らしいですね。(※m(_ _)m大ウソです。この記事を参照ください)
■同サーバにあるJSON形式を吐き出すPHPスクリプトから取得 [デモ]
var MyDataStore = new Ext.data.Store({
proxy: new Ext.data.HttpProxy({
url: './json.php'
}),
reader: new Ext.data.JsonReader({
root: 'humandata',
totalProperty: 'totalCount',
fields: [
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]
})
});
MyDataStore.load();json.php
<?php
header("Content-Type:application/x-json; charset=UTF-8");
echo <<<E
{
"totalCount":"17",
"humandata": [
{
"name": "佐藤",
"gender": "男",
"tel": "090-8580-4820",
"mail": "wxqm@viutqz.com",
"info": "リラックスべたで、怠けることを知らない。"
},
…省略
]
}
E;
?>同サーバでかつHTTP経由で実行する必要があるので「Ext.data.HttpProxy」でOK。問題なく取れました。この場合は「stcCallback1001()」コールバック関数でくくってはいけません。
ただし「Ext.data.ScriptTagProxy」の場合はくくる必要があります。ちょっとややこしいかもしれませんが、混乱しないように整理して把握しておかないと、取得できん!と取り乱すことになりかねません。
■同サーバにあるXML形式を吐き出すPHPスクリプトから取得 [デモ]
var MyDataStore = new Ext.data.Store({
proxy: new Ext.data.HttpProxy({
url: './xml.php'
}),
reader: new Ext.data.XmlReader({
record: 'humandata',
totalRecords: 'totalCount',
fields: [
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]
})
});
MyDataStore.load();あれ?問題ないだろうと思ったのですが、取れませんと表示されません。XMLHttpRequest接続でデータは取得できているみたいなのですが、レンダリングされないですね。どこが悪いんだろう…
色々やっていたら表示されました。「Content-Type:text/xml」として吐き出さなければならないみたいです。あぁAPIドキュメントにもきっちり書かれていますねorz
「Content-Type:text/html」としてました。。。(JSONの方ではそれでいけてたので、というかここらへんちゃんとわかってねぇなぁorz)
xml.php
<?php
header("Content-Type:text/xml; charset=UTF-8");
echo <<<E
<?xml version="1.0" encoding="UTF-8" ?>
<list>
<init>
<totalCount>17</totalCount>
</init>
<humandata>
<name>佐藤</name>
<gender>男</gender>
<tel>090-8580-4820</tel>
<mail>wxqm@viutqz.com</mail>
<info>リラックスべたで、怠けることを知らない。</info>
</humandata>
…
</list>
E;
?>ちなみに補足だが、データの種類、取得方法によっていくつかの「Ext.data.〜」組み合わせパターンができると思う。
あるパターンの組み合わせをひとつにしたクラスが予め用意されてあるものもあるので一応見ておきましょう。
「Ext.data.JsonStore」=「Ext.data.Store」+「Ext.data.HttpProxy」+「Ext.data.JsonReader」 [デモ]
var MyDataStore = new Ext.data.JsonStore({
url: './data.json',
root: 'humandata',
totalProperty: 'totalCount',
fields: [
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]
});
MyDataStore.load();「Ext.data.XmlStore」=「Ext.data.Store」+「Ext.data.HttpProxy」+「Ext.data.XmlReader」 [デモ]
var MyDataStore = new Ext.data.XmlStore({
url: './data.xml',
record: 'humandata',
totalRecords: 'totalCount',
fields: [
{ name:'name' },
{ name:'gender' },
{ name:'tel' },
{ name:'mail' },
{ name:'info' }
]
});
MyDataStore.load();どちらもかなり簡潔にかけるのでソースが短くなってよいが、今でこそなるほどとわかるからいいものの最初これから入ったら絶対訳わかんなくなるに違いない。
とまぁこんな感じですねぇ。
長い!疲れた(;´ρ`)