Tuesday, July 04, 2006

Dojo ScriptSrcIO

สืบเนื่องมาจากงาน codefest ที่ติดใจว่ายังทำ Cross Domain javascript ไม่สำเร็จ

ผมเคยเขียนเรื่อง cross domain javascript ไปทีแล้ว
Yahoo Web Services + JSON + Cross domain javascript

วิธีที่เคยเขียนถึงนั้น จริงๆ ก็ไม่ยากเย็นอะไร
แต่มีวิธีที่คิดว่าดีกว่า นั่นก็คือใช้ Dojo
Dojo เตรียม feature dojo.io.ScriptSrcIO ให้เราเรียบร้อยแล้ว
(ซึ่งเดาว่า คงใช้วิธีแบบเดียวกับที่เคยเขียนไปนั่นแหล่ะ เพียงแต่ฉลาดกว่า และทำได้หลายหลายแบบกว่า)
เหลือแต่ว่าหาวิธีใช้มันให้ได้เท่านั้นเอง
วันนี้ผมก็เลยนั่ง งม หาวิธีใช้

หลังจากมั่วอยู่นาน ไม่เกิดผลสักที จนเกือบยอมแพ้ไปแล้ว
google ก็เป็นใจ ส่งตัวอย่างที่ชัดๆมาให้ดูจนได้
หลังจากทดลอง run ตัวอย่าง ก็เลยรู้ว่าท่ีทดสอบไม่สำเร็จ
เป็นเพราะผมใช้ browser ไปเปิด html file จาก filesystem ตรงๆ
โดยไม่ผ่าน web server,
การเปิด file ตรงๆ จะทำให้ dojo ไม่สามารถ solve หา src ที่มันต้องการได้
(เนื่องจากเวลา dojo solve หา src มันจะใช้ xmlhttprequest ในการค้นหา)
UPDATE:
ผิดที่วิธี config ของผมเอง ไม่ได้ผิดที่การเรียกใช้โดยตรงจาก filesystem


ลองดูตัวอย่างเต็มๆ ได้ที่ site ของหนุ่มญี่ปุ่นคนนี้
http://d.hatena.ne.jp/shinichitomita/20060522/1148276164


ที่นี้ลองมาทำความเข้าใจดูบ้าง
เริ่มแรกสุด ก็คือวิธีที่ใช้ dojo.io.bind
dojo.io.bind({
url: 'http://del.icio.us/feeds/json/'+deliciousId,
transport: "ScriptSrcTransport",
jsonParamName: "callback",
load: function(type, data, event, kwArgs) {
renderPosts(data);
}
});

จะเห็นว่า เราเลือกใช้ transport เป็น "ScriptSrcTransport"
เจ้า dojo.io.bind ออกแบบมาให้เราสามารถ switch วิธีการที่ใช้
ติดต่อกับ server ได้
โดยค่า default ของมันก็คือ XMLHTTPTransport
ซึ่งก็คือการใช้ XmlHttpRequest นั่นเอง

ประเด็นถัดมา ก็คือค่า result ที่ได้
พอได้มาแล้ว จะนำมาแสดงอย่างไร
ลองทดสอบนำ url "http://del.icio.us/feeds/json/pokpok" มา run ดู
จะพบว่ามัน return code มาหน้าตาแบบนี้

if(typeof(Delicious) == 'undefined')
Delicious = {};
Delicious.posts = [{"u":"http://sawmill.sourceforge.net/","d":"sawfish: an extensib .... }];

จะเห็นว่าถ้า call ได้สำเร็จ เราจะได้ ตัวแปร Delicious.posts มาใช้
แต่ปัญหาก็คือ เนื่องจาก nature ของการ call แบบนี้ มันเป็น Asyncronous
เราจะรู้ได้อย่างไรว่า Delicious.posts ถูก assign เรียบร้อยแล้ว

พวก json service เห็นปัญหานี้ ก็เลยออกแบบ service ของตนให้ pass ค่า callback ได้ด้วย
ทดลองเรียก
"http://del.icio.us/feeds/json/pokpok?callback=show"
ผลลัพท์ที่ได้จะมีหน้าตาแบบนี้

show([{"u":"http://sawmill.sourceforge.net/","d":"sawfish: an extensib ...."}];);

Note: มีศัพท์ที่เขาใช้เรียกวิธีนี้ว่า JSONP
อ่านรายละเอียดได้ที่นี่ Remote JSON - JSONP


ในการใช้ Dojo ScriptSrcIo
เราสามารถเลือกวิธี callback ได้เหมือนกัน
โดยการใส่ parameter jsonParamName: "callback"
ค่า callback ที่ใส่นี้เป็นชื่อ param ที่ remote service รับนะ
ไม่ใช่ชื่อของ javascript function ที่ต้องการให้ call
ผลลัพท์ที่ได้จาก remote service ก็จะถูกส่งต่อให้
function ที่ระบุไว้ที่ parameter load: function(type, data, event, kwArgs) ทำงาน
โดย data ก็คือ javascript object ที่ service ตอบกลับมา

เพื่อให้แม่นยิ่งขึ้น ผมเลยทดลองเขียน service hello world ด้วย rails ดู
ตัว view หน้าตาแบบนี้
​​
<%= params[:callback] %>({result: "helloworld"})

ส่วน client ที่ call ก็หน้าตาแบบนี้
function test() {
dojo.io.bind({
url: 'http://erp:3000/test',
transport: "ScriptSrcTransport",
jsonParamName: "callback",
load: function(type, data, event, kwArgs) {
alert(data.result);
}
});
}

Related link from Roti

No comments: