2.3. Views
2.1 Foreword
As you will see we got several views and the html code is a lot hierarchised. I’ve found that when you want to use ajax methods you need to have a good html tree.
2.2 list.rhtml
Copy’n paste the following code in the app/views/message/list.rhtml file.
<%= render 'message/new' %>
<div id="messages">
<%= render 'message/message_list' %>
</div>
Simple isn’t it ?
render 'message/new' render the app/views/message/new.rhtml file, render 'message/message_list' render the app/views/message/message_list.rhtml file.
2.3 new.rhtml
Copy’n paste the following code in the app/views/message/new.rhtml file.
<%= form_remote_tag(
:url => {:controller => "message", :action => "new_with_ajax"},
:html => {:class => 'message'},
:update => 'messages',
:loading => 'Toggle.display(\'new-message\'); $(\'new-message-desc\').innerHTML = \'Saving ...\'',
:complete => "$('new-message-desc').innerHTML = 'Create a new message';"
) %>
<div class="info">
<h4>
<span id="new-message-desc">Create a new message</span>
<a class="expander" href="#" onclick="Toggle.display('new-message');
Field.focus('new-message-title'); return false">»</a>
<!--
a simple link to hide or display the form
-->
</h4>
</div>
<div id="new-message" class="content" style="display: none">
<%= text_field 'message', 'title', :id => 'new-message-title' %><br />
<%= text_area 'message', 'note', :id => 'new-message-note' %><br />
<label for="new-message-author">Your name :</label>
<%= text_field 'message', 'user', :id => 'new-message-author' %><br />
<input type="submit" value="submit"/>
</div>
<%= end_form_tag %>
So what does this thing do ? When you load the page the form is hidden (display: none), the link :
<a class="expander" href="#" onclick="Toggle.display('new-message');
Field.focus('new-message-title'); return false">»</a>
Allow us to make it visible.
Then you can fill the form. The form is defined by the form_remote_tag method :
<%= form_remote_tag(
:url => {:controller => "message", :action => "new_with_ajax"},
:html => {:class => 'message'},
:update => 'messages',
:loading => 'Toggle.display(\'new-message\'); $(\'new-message-desc\').innerHTML = \'Saving ...\'',
:complete => "$('new-message-desc').innerHTML = 'Create a new message';"
) %>
It does the same thing as the regular form_tag except that it use ajax to handle all the processing when you click the submit button. What are the options ?
pdate : is the id of the html node that we will update
rl : the url that will be called by the form. Here we call the new_with_ajax action of the message controller.
oading : allow us to specify things that will be done while the whole thing is processed, in this case we tell to the user that we are saving his message.
omplete : same idea, it allows us to set things that will be done when the processing is done, here we tell the user that he is now able to add a new message.
tml : if you are not familiar with this one it’s a way to pass html option such as d, tyle, ... Check the rails api doc for more details.
Check the following links to get more info about the options :- http://developer.apple.com/internet/webcontent/xmlhttpreq.html
- http://wiki.rubyonrails.com/rails/show/How+to+use+the+Ajax+helpers
def new_with_ajax
message = Message.new(@params['message'])
if message.save
# get the new collection
@messages = Message.find_all
# render the page content
render 'message/message_list'
end
end
So it update the messages div with the rendering of message/message_list (ie update the list).
2.4 message_list.rhtml
Copy’n paste the following code in the app/views/message/message_list.rhtml file.
<% @messages.each { |message| %>
<div id="message<%= message.id %>" class="message">
<h3><%= message.title %></h3>
<span class="content"><%= message.note %></span>
<span class="author"><%= message.user %></span>
<%= link_to_remote "Remove",
:url =>{
:controller =>"message",
:action=>"destroy",
:id=>message.id},
:update=>"messages",
:loading => '$(\'message' + message.id.to_s + '\').innerHTML = \'Removing ...\'',
:html => {:id => 'remove-message'+message.id.to_s}
%>
</div>
<% } %>
This one is more simple. For each message in @messages it display a div. Each div got a unique id composed by message plus the message id. It allows us to track each message in the page. And because we are now able to find each message in the html tree we can remove them.
Here is the aim of :
<%= link_to_remote "Remove",
:url =>{
:controller =>"message",
:action=>"destroy",
:id=>message.id},
:update=>"messages",
:loading => '$(\'message' + message.id.to_s + '\').innerHTML = \'Removing ...\'',
:html => {:id => 'remove-message'+message.id.to_s}
%>
Each remove link call the destroy method passing the id of the message. While the server is processing the Removing … text replace the message content.
When it’s done, the messages div will be updated in the same way as in the new.rhtml view.