Thursday, December 22, 2005

JavaScriptGenerator (RJS Template)

JavaScriptGenerator เป็น Plugin ของ Rails
ที่ช่วยให้เราเขียน ajax ได้สะดวกขึ้น
ลองดูตัวอย่าง

สมมติว่าเราต้องการให้มีหน้าจอ Project Listing
ที่ user สามารถ add project ใหม่ๆได้



เมื่อ user กด add ก็จะแสดง form ขึ้นมา



เมื่อ user กด "add" ก็จะ validate
ว่า project name เป็นค่าว่างหรือไม่
ถ้า validate ผ่าน ก็จะ update "project listing" ให้



กรณีีที่ไม่ผ่าน
ก็จะ แสดง error message



ถ้า user กด cancel ก็จะซ่อน form
และ error message

มาดูว่า ถ้าเขียนโดยใช้ JavaScriptGenerator แล้ว
จะต้องทำอย่างไรบ้าง

ขั้นที่ 1 ไป download plugin มาติดตั้งให้เรียบร้อยก่อน
svn ของ RJS Template อยู่ที่
http://wiki.rubyonrails.org/rails/pages/Plugins

ขั้นที่ 2 implement controller
เริ่มทำหน้าจอ listing ก่อน
class RjsController < ApplicationController

def index
list
render :action => 'list'
end

def list
@projects = Project.find(:all)
end

end

โดย rhtml จะมีหน้าตาแบบนี้
<h4>Listing projects</h4>
<ul id="list">
<% for project in @projects %>
<li>
<%=h project.name %></td>
</li>
<% end %>
</ul>

<div id="post_error">
</div>

<div id="input" style="display:none">
<%= form_remote_tag (
:url => { :action => :new }) %>
<label for="name">Name :</label>
<%= text_field_tag ('name', '', :id=>'name-field') %>
<%= submit_tag "add", :id=>'project-add'%>
<%= end_form_tag %>
<%= link_to_remote ('Cancel',
:url => {:action => :cancel_new}) %>
</div>
<br />

<div id="add_link">
<%= link_to_remote ('New project',
:url => { :action => :display_new }) %>
</div>

จะสังเกตเห็นว่า เรามี ul
ที่มี id => "list"
และก็มี div block
id => "post_error" ไว้แสดง error message
id => "input" ส่วนของ ajax form
id => "add_link" ส่วน link ที่เป็นจุดเริ่มต้นการทำงาน

ขั้นที่ 3 เมื่อ user เลือก link "new project"
ก็จะเกิด ajax request "display_new" ไปที่ server
(จริงๆแล้ว ขั้นนี้ทำเป็น javascript ธรรมดาก็ได้
แต่อยากลอง feature ก็เลยทำเป็น ajax)
controller เราก็จะ define method ดังนี้
class RjsController < ApplicationController

...

def display_new
end

end

ส่วน view ที่ render กลับ
เราจะใช้ rjs template เข้ามา render แทน
โดยแทนที่จะใช้ file ที่นามสกุล rhtml
เราจะตั้งเป็นนามสกุล rjs แทน
page.show('input')
page.hide('add_link')
page.visual_effect :highlight, 'input', :duration => 3

จาก code ข้างบน rjs จะทำการ generate
javascript ตอบกลับไป
โดย page.show ก็คือสั่งให้ DOM Element ที่ต้องการ show ขึ้นมา
ส่วน visual effect ก็คือ ไปเรียกใช้ Mir.aculo.us script ให้ทำงาน

ขั้นที่ 4 ถ้า user submit form เข้ามา
class RjsController < ApplicationController

...

def new
if params[:name] == nil or params[:name] == ""
render :action => :new_error
else

## do some business logic here.

render :action => :new_success
end
end

end

โดย rjs template กรณี success จะเป็นดังนี้
page.insert_html :bottom, 'list',
content_tag("li", params[:name])
page.visual_effect :highlight, 'list', :duration => 3

กรณีที่มี error ก็จะเป็นดังนี้
page.replace_html 'post_error',
'Project Name must specific!!!'
page.visual_effect :highlight, 'post_error', :duration => 3


ดูๆแล้วก็ง่ายดีเหมือนกัน
ถ้าอยากรู้ว่าง่ายแค่ไหน ก็ต้องลองเขียน version ที่ไม่ใช้ rjs
เปรียบเทียบกันดู
ผมลองแล้ว แต่ไม่บอก :)

Related link from Roti

No comments: