Thu, 12 Jan 2006 13:57:00 GMT

.rjs and link_to_function

A neat little trick is that .rjs templates can be used to generate local javascript functions and be invoked without doing a server roundtrip.

playground_controller.rb

class PlaygroundController < ApplicationController
  def rjs
     response.headers['content-type'] = 'text/html'
  end
end

rjs.rhtml

<html>
<head>
  <%= javascript_include_tag :defaults %>  
</head>
<body>
<h1 id='header'>Javascript function test</<html>
<head>
<%= javascript_include_tag :defaults %>
</head>
<body>
<h1 id
=
header>Javascript function test</h1>

<%= link_to_function(‘Add’, ‘add_item()’ ) -%> |
<%= link_to_function(‘Clear’, ‘clear_list()’) >
<ul id=‘list’
/>
<script type=text/javascript>
<= render :partial => functions, :type => rjs >
</script>
<script type=‘text
/
javascript>
<
= # Note: following javascript is run when the page is loaded.
update_page do |page|
3.times { page.call
add_item }
end
%>
</script>
</body>
</html>

The rjs method in the PlaygroundController set’s the content-type as we perform a render of an rjs from within a .rhtml and this seems to change the content-type, so we need to reset it.

_function.rjs

page << 'function add_item() {'
  page.insert_html :bottom, 'list', content_tag('li', 'item', :id => 'list_item' )
  page.visual_effect :highlight, 'list', :duration => 3
page << '}'page << function add_item() {
page.insert_html :bottom, list, content_tag(li, item, :id => list_item )
page.visual_effect :highlight, list, :duration => 3
page << }

page << function clear_list() {
page.replace_html :list, ""
page.visual_effect :highlight, list, :duration => 3
page << }

In the partial function.rjs we insert the function declaration before writing to the page object. This allows us to invoke the additem _ and clear_list _ methods using the link_to_function _ from in the .rhtml file. Note also in the .rhtml file we invoke directly the update_page method to insert three calls to add_item().

The generated html files looks like this

<html>
<head>
  <script src="/javascripts/prototype.js" type="text/javascript"></script>
<script src="/javascripts/effects.js" type="text/javascript"></script>
<script src="/javascripts/dragdrop.js" type="text/javascript"></script>
<script src="/javascripts/controls.js" type="text/javascript"></script>  
</head>
<body>
<h1 id='header'>Javascript function test</h1>

<a href="#" onclick="add_item(); return false;">Add</a> | 
<a href="#" onclick="clear_list(); return false;">Clear</a>
    <ul id='list' />
<script type='text/javascript'>
  function add_item() {
new Insertion.Bottom("list", "<li id=\"list_item\">item</li>");
new Effect.Highlight('list',{duration:3});
}
function clear_list() {
Element.update("list", "");
new Effect.Highlight('list',{duration:3});
}
</script>
  <script type='text/javascript'>
  add_item();
        add_item();
        add_item();
  </script>  
</body>
</html>

Comments

  • Tommy says
    Thanks a lot for posting this. This helped me get started with RJS. I'd like to use this technique to add multiple select boxes to a form and I'd like to be able to pass a variable to the rendered javascript. For example, add_select(index, var) ... select(:date, :day, :index=> index) ... hidden_field(:foo, :bar, :index=> index, :value=>var) } is this possible? When I try to pass the variable, rails won't render the page and says index and var don't exist.
  • daniel wanja says
    As you see in this article the add_item function defined in the _function.rjs doesn't take a parameter. If I understand well your question is how to pass a 'javascript' parameter to this function that can be referenced with the the rjs statements, thus allowing to write pretty powerful javascript functions by only using rjs. Like you, I am not sure that this is possible witht the current implementation of the rjs functionality, besides writting the whole function using the page << approach, which defeats the purpose of using rjs. This can be a mind bender as we are using rails to generate javascript that will run in the client browser, and the rjs functionality was tailored to allow to manipulate the DOM by injecting dynamic html/javascript that is generated on the server and returned and run on the client. In short there is a stage where I simply create a javascript library to manipulate the page. So a server call can simply invoke a predefined javascript function, and a javascript function can also be invoked to 'assemble' the data to be returned to the server. If found the news Rails 1.1 documentation pretty instructive. The page.select is pretty powerfull and gives access to a dom element. This is one possibility to pass data to a function. http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper/JavaScriptGenerator/GeneratorMethods.html for some more information.
  • john@venuesoftware.com says

    DONT USE BLACK BACKGROUNDS! Making things difficult to read is not useful!

  • Adam B says

    Since when is a black background ‘difficult to read’? If anything the opposite is true — white backgrounds mean more light going into your eyes, increasing eyestrain. The best colours for reading off a monitor all day are green text on a black background. This is the reason early computers (and many terminals) use or default to that scheme. I assure you, they did studies!

    Found this article looking for something completely different and happened to learn something, thanks. :)