Ruby on Rails
How to use the Ajax helpers (Version #13)

Rails now provides(as of 0.11.0) a number of useful tools to simplify working with “Ajax”.

The API documentation is available: http://rails.rubyonrails.com/classes/ActionView/Helpers/JavaScriptHelper.html

The example given here is to delete records, but you could easily modify it to change status, add records, or even render a partial and dump it into a div.

Initializing the Ajax code

You must include the javascript code in your view for the Ajax functions to be available in that view. The best place for this is in the <head> tag like so:

Example using define_javascript_functions (the ok method)


<html>
<head>
..
<%= define_javascript_functions %>
..
</head>
<body>

What is the difference between define_javascript_functions and javascript_include_tag ?

define_javascript_functions pastes all of the required Javascript code right into your view. All 21kb of it. javascript_include_tag on the other hand simply creates a <script> tag that links to the javascript files like prototype.js, controls.js, etc rather than printing it all out in the HTML <head>.

Example using javascript_include_tag (the best method)


<html>
<head>
..
<%= javascript_include_tag  :defaults %>

</head>
...

produces


<html>
<head>
..
<script type="text/javascript" src="/javascripts/prototype.js"></script>
...
<script type="text/javascript" src="/javascripts/controls.js"></script>
</head>
...

Using javascript_include_tag allows for quicker downloads since the script can be cached by the browsers instead of adding an extra ~20kb to every page.

Where do you want to go today?

There are two options here. Either you can return a snippet of HTML and fill a container (like a div or table cell) with it; and/or, you can run a javascript function.

Javascript Functions

You’ll want to create the javascript functions if you want the code to do anything. Following on from the other Ajax howto HowToUseAjaxToRemoveARecordWithoutReloadingThePage, here’s similar functionality but with the helpers.

First, let’s say we have some divs with items in them, and a “remove” link on each div.


<div id="animal<%= animals.id%>">
  <%= animals.name %>  
  <a href='#'>(remove)</a>
</div>

The javascript function should add the words, “Removing..” to the div, remove the database item, then hide the div once it’s done. This gives the appearance of being “deleted”, and stops the user refreshing the page (which will cancel the http request).

To hide the div, we’ll just empty its contents.

Now for the javascript to change the text of the div so we have some status goin’ on. This function allows you to pass a node, or a string containing the id of a node.


function status(node)
{
  if (!node) return false;
  if (typeof node == 'string')
    node = document.getElementById(node);
  if (node) node.innerHTML = 'Removing ..' + node.innerHTML
}

Note: Using the function name ‘status’ throws an error in Safari.

Calling the request

Now for the Rails happiness!

Replace the link in the div with this simple code: (don’t worry, we’ll explain it more below)


<%= link_to_remote "Remove",
    :url=>{
        :controller=>"animals",
        :action=>"destroy", 
        :id=>animal.id},
    :update=>"animal#{animal.id}",
    :loading=>"status('animal#{animal.id}')" 
%>

Wtf?

The link_to_remote arguments are as follows:

  • :update
  • :url
  • :uninitialized,
  • :loading
  • :loaded
  • :interactive
  • :complete

The last 5 relate to the status of the HTTP request; however, not all of these are compatible across all browsers, and all you can really rely on are :loading, and :complete (status 1, and 4, respectively).

  • update Denotes which HTML node to return the final text to. In this case (destroy) we want to ‘hide’ the <div id=" #{animal#id}">, so the view for animals will be an empty file.
  • url You can probably guess this one. Takes the same arguments as url_for or link_to.
  • loading This is the name of the javascript callback function to call once the page is set loading. In this case, we call the status function.
  • complete The name of the javascript callback function to call once the request is complete.

There are more functions (such as link_to_function) as well as a form serializer in this wonderful helper library..

Using the form serializer

Returns a form tag that will submit using XmlHTTPRequest in the background instead of the regular reloading POST arrangement. This is useful when using <input> buttons instead of just text links with link_to_remote.

Just start your form with:


<%= form_remote_tag :update => 'id_of_element_where_you_like_the_response_to_go', 
  :url => { :action => 'your_action' } %>

There is also an option :position (before, after, top, bottom) which places the response html to those positions relative to the element you specify with :update. These positions indicate where in the DOM the returned html is to be inserted, whether inside the named element or outside.

  • before inserts the returned text Before the named element, but not contained within it.
  • top inserts the returned text at the top of the named element, contained within the named element
  • bottom inserts the returned text at the end of the named element, contained within the named element
  • after inserts the returned text below the named element, but not contained within it.

This will automagically make the form work with Ajax remoting. No special changes need to be made to your submit button. All variables will be available in @params.

Modify your controller

You’ll need to modify the action so that it returns the correct response. You may even need a new action.

If you are deleting a record, you’ll just return an empty string so that the DIV is effectively removed.

render_text ""

If you are updating or inserting a record, you’ll want to return a full record, so, a good way to do this, is to have the DIV contents rendered as a partial ( <%= render_partial "mydiv", @animal %> ) and render the exact same partial from your action. Less programming!

More fun stuff with the Ajax helpers

Rails now provides(as of 0.11.0) a number of useful tools to simplify working with “Ajax”.

The API documentation is available: http://rails.rubyonrails.com/classes/ActionView/Helpers/JavaScriptHelper.html

The example given here is to delete records, but you could easily modify it to change status, add records, or even render a partial and dump it into a div.

Initializing the Ajax code

You must include the javascript code in your view for the Ajax functions to be available in that view. The best place for this is in the <head> tag like so:

Example using define_javascript_functions (the ok method)


<html>
<head>
..
<%= define_javascript_functions %>
..
</head>
<body>

What is the difference between define_javascript_functions and javascript_include_tag ?

define_javascript_functions pastes all of the required Javascript code right into your view. All 21kb of it. javascript_include_tag on the other hand simply creates a <script> tag that links to the javascript files like prototype.js, controls.js, etc rather than printing it all out in the HTML <head>.

Example using javascript_include_tag (the best method)


<html>
<head>
..
<%= javascript_include_tag  :defaults %>

</head>
...

produces


<html>
<head>
..
<script type="text/javascript" src="/javascripts/prototype.js"></script>
...
<script type="text/javascript" src="/javascripts/controls.js"></script>
</head>
...

Using javascript_include_tag allows for quicker downloads since the script can be cached by the browsers instead of adding an extra ~20kb to every page.

Where do you want to go today?

There are two options here. Either you can return a snippet of HTML and fill a container (like a div or table cell) with it; and/or, you can run a javascript function.

Javascript Functions

You’ll want to create the javascript functions if you want the code to do anything. Following on from the other Ajax howto HowToUseAjaxToRemoveARecordWithoutReloadingThePage, here’s similar functionality but with the helpers.

First, let’s say we have some divs with items in them, and a “remove” link on each div.


<div id="animal<%= animals.id%>">
  <%= animals.name %>  
  <a href='#'>(remove)</a>
</div>

The javascript function should add the words, “Removing..” to the div, remove the database item, then hide the div once it’s done. This gives the appearance of being “deleted”, and stops the user refreshing the page (which will cancel the http request).

To hide the div, we’ll just empty its contents.

Now for the javascript to change the text of the div so we have some status goin’ on. This function allows you to pass a node, or a string containing the id of a node.


function status(node)
{
  if (!node) return false;
  if (typeof node == 'string')
    node = document.getElementById(node);
  if (node) node.innerHTML = 'Removing ..' + node.innerHTML
}

Note: Using the function name ‘status’ throws an error in Safari.

Calling the request

Now for the Rails happiness!

Replace the link in the div with this simple code: (don’t worry, we’ll explain it more below)


<%= link_to_remote "Remove",
    :url=>{
        :controller=>"animals",
        :action=>"destroy", 
        :id=>animal.id},
    :update=>"animal#{animal.id}",
    :loading=>"status('animal#{animal.id}')" 
%>

Wtf?

The link_to_remote arguments are as follows:

  • :update
  • :url
  • :uninitialized,
  • :loading
  • :loaded
  • :interactive
  • :complete

The last 5 relate to the status of the HTTP request; however, not all of these are compatible across all browsers, and all you can really rely on are :loading, and :complete (status 1, and 4, respectively).

  • update Denotes which HTML node to return the final text to. In this case (destroy) we want to ‘hide’ the <div id=" #{animal#id}">, so the view for animals will be an empty file.
  • url You can probably guess this one. Takes the same arguments as url_for or link_to.
  • loading This is the name of the javascript callback function to call once the page is set loading. In this case, we call the status function.
  • complete The name of the javascript callback function to call once the request is complete.

There are more functions (such as link_to_function) as well as a form serializer in this wonderful helper library..

Using the form serializer

Returns a form tag that will submit using XmlHTTPRequest in the background instead of the regular reloading POST arrangement. This is useful when using <input> buttons instead of just text links with link_to_remote.

Just start your form with:


<%= form_remote_tag :update => 'id_of_element_where_you_like_the_response_to_go', 
  :url => { :action => 'your_action' } %>

There is also an option :position (before, after, top, bottom) which places the response html to those positions relative to the element you specify with :update. These positions indicate where in the DOM the returned html is to be inserted, whether inside the named element or outside.

  • before inserts the returned text Before the named element, but not contained within it.
  • top inserts the returned text at the top of the named element, contained within the named element
  • bottom inserts the returned text at the end of the named element, contained within the named element
  • after inserts the returned text below the named element, but not contained within it.

This will automagically make the form work with Ajax remoting. No special changes need to be made to your submit button. All variables will be available in @params.

Modify your controller

You’ll need to modify the action so that it returns the correct response. You may even need a new action.

If you are deleting a record, you’ll just return an empty string so that the DIV is effectively removed.

render_text ""

If you are updating or inserting a record, you’ll want to return a full record, so, a good way to do this, is to have the DIV contents rendered as a partial ( <%= render_partial "mydiv", @animal %> ) and render the exact same partial from your action. Less programming!

More fun stuff with the Ajax helpers