Archive for the ‘Javascript’ Category

The REAL Rails AJAX Select Control Tutorial

April 1, 2006 in Javascript,Programming,Ruby,Ruby on Rails | Comments (0)

I’ve been trying for a while to implement functionality in Rails where, when the value of one selector is changed by the user, a related selector is refilled with associated data. I’m rewriting one of my PHP applications (The CIty of Villains Registry) in Rails, so I’ve already implemented similar functionality in PHP. Unfortunately, the amount of documentation out there for this sort of thing is rather sparse, and leaves a couple of wide holes open for developers to fall into. I finally got it to work, but it was tough pulling all of the information together. I figured it would be worth my while to post what I did to help others wrestling with the same thing (and there appear to be quite a few).

Create a Partial Template to Render your Select Control

For my application, there is one select control for choosing a hero archetype. Two other selectors let you choose primary and secondary powersets. We’ll just concentrate on the primary powerset selector for this exercise. When the page loads, whatever value is in the archetype selector will determine what values should be available in the powerset selector, so my template does a quick find based on whatever archetype ID is buried in the hero model and generates a select control with the matching powerset names and ID’s.

<%=select(“hero”, “primary_powerset_id”, ArchetypePrimary.find_all_by_archetype_id(archetype_id).collect {|p| [ p.powerset.name, p.powerset_id ] })%>

For my application, this got saved as app/views/hero/_primary_powerset_selector.rhtml

Modify your Page Template to render your Select Control

Now that we have a partial template, we need to get it to render in the parent page. Keep in mind, though, that with an AJAX call, we’re going to be replacing the content of an object on the page with the rendered output, so we’re going to bury the render inside a span tag. We’ll use that name of that tag later on when we make our AJAX call.

<span id=’primary_powerset_selector’>
<%= render :partial => ‘primary_powerset_selector’, :locals => {:archetype_id => @hero.archetype_id}%>
</span>

In my application, this code goes in the app/view/hero/_form.rhtml file where I want the select control to appear.

Create an Action to Render your Partial Template

What we’ve done so far will make the filtered selector appear on the page, loaded with the filtered set of results. In order to make it dynamic, we have to build a custom action into our controller that knows how to refresh the select control. It will take the new archetype ID as an argument, then render our template to produce a select control. It’s a pretty simple call, it just takes the passed argument and renders the partial:

def fill_primary_powerset_box
render(:partial => ‘primary_powerset_selector’, :locals => {:archetype_id => @params[:archetype_id]})
end

In my application, this method was added to the app/controllers/hero_controller.rb file.

Add the AJAX Call to your Page Template

Everything is in place, so now we can ask Rails to render the AJAX call that will dynamically render the select control into our span. Somewhere after the span, drop something like this into your template:

<%= observe_field(
‘hero_archetype_id’,
:update => :primary_powerset_selector,
:url => {:controller => ‘hero’, :action => :fill_primary_powerset_box},
:with => “‘archetype_id=’ + value”)
%>

So what’s worth noticing is the following: I’m passing in the name of the selector that is being watched (when my hero_archetype_selector changes I want this event to be fired), I’m giving it the name of the span I want to be updated with the new content (primary_power_selector is the name of my span), I’m telling it to user the hero controller and call the fill_primary_powerset_box action, and I’m handing the value of the control that changed as an argument named archetype_id.

If you’ve been trying to figure this stuff out for any time at all you’re going to notice one that is missing: The frequency parameter. Every example I have seen for observe_field passes in a frequency parameter, but you only need to use this if you really need to be polling, like maybe you’re pulling in search result as the user types, or dynamically rendering the text being typed somewhere else on the page. You don’t need it to link two select controls together. Leaving this parameter out makes the event fire when the value in the selector changes. I had started out using a frequency of zero, which would make the event fire when it should, but the Prototype library would throw an error. This is because it was sending my zero as the callback instead of a function reference. Just leave it out and you’ll be fine.

It was a lot of working figuring out how to set this up right for the incredibly small amount of code it actually takes to pull it off. Hopefully this will make it easier for you set up a similar configuration in your own applications.

Caveats

Now that I have it working I do notice that the callback is considerably slower than my homebrew PHP version was. Maybe it’s because I’m on a shared server, and maybe it’s because I’m running in dev mode right now. I have to poke around at it a little bit more.

Helpful resources:

  • Rails Hosting – This site has some good examples of using the Prototype library for AJAX and client side scripting with Ruby.
  • Using Prototype v1.4.0 – This helped me ultimately deduce the problem in my rendered calls since it describes the actual constructors and arguments to the Prototype objects. I could see where Form.Element.EventObserver did not take a frequency argument, and that my frequency value of zero was being passed in place of the callback.
  • Rory Hanson’s – This was where I started, since it came up first in Google. It gives some good examples of how to set up the code. You’ll notice, however, the number of people having difficulty making it work.
  • Adam C. Hegedus’s Blog Entry – This one really helped me get started, picking up where Rory’s blog left off.

I hate being lied to

February 1, 2005 in Javascript | Comments (0)

Maybe I’m just stupid, but the code example on this page did not provide a valid sample for building a test for isNaN() in Javascript.

Let’s say an empty string has been passed in, and you want to use a zero in its place. According to this sample, you should be able to do this:

var t = "";
var r = (isNaN(t) ? 0 : parseInt(t));

In my experience, with Microsoft Internet Explorer 6’s version of Javascript, this did not work. I had to use parseInt() to convert the string first, which returns NaN if the string cannot be converted. The proper code looks like this:

var t = "";
var r = (isNaN(parseInt(t)) ? 0 : parseInt(t));

So either this page is incorrect, or there is a discrepancy between Microsoft’s version of Javascript (which they claim to be a compliant ECMAScript implementation, I believe). Don’t know which, but it was a bit annoying.


A Simple Javascript Queue Object

January 8, 2004 in Javascript,Programming | Comments (1)

I needed a queue to use in a script. I looked at a few online, but you know how it is… I decided to write my own.



// This is a simple implementation of a first-in/first-out queue
function Queue(Name)
{
  this.Name = Name; // Makes it pretty when you print the contents
  this.Stack = new Array();
  this.Enqueue = function(Item)
  {
    // Tack the new entry onto the end of the array
    this.Stack[this.Stack.length] = Item;
    return this;
  }
  this.Dequeue = function()
  {
    // Remove the first entry from the array and return it
    if (this.Stack.length > 0)
    {
      var Result = this.Stack[0];
      this.Stack = this.Stack.slice(1);
      return Result;
    }
    return null;
  }
  this.toString = function()
  {
    Result = this.Name + "Queue Contents:n";
    for (var x = 0; x < this.Stack.length; x++)
    {
      Result += "t" + this.Stack[x];
    }
    return Result;
  }
}

// This object is used to store items that are going to be piled up on a queue
function QueuedHours(Point, Amount)
{
  this.Point = Point;
  this.Amount = Amount;
  return this;
}

Usage is pretty straightforward. Just create an instance, then enqueue and dequeue any kind of objects you want. It can certainly be extended, but for a simple, first-in, first-out queue component, it works pretty well.


var MyQueue = new Queue("test-queue");
MyQueue.Enqueue("Test object");
alert(MyQueue.toString());
alert(MyQueue.Dequeue());
alert(MyQueue.toString());

Note that for my purposes, the number of objects in the queue will never be very large. I’ve seen other implementations that use a simple linked list to pull it off. That would make better sense for a larger queue than slicing up the array every time you access it.


debugger: The Magic Word

January 5, 2004 in Javascript,Programming | Comments (0)

I used to do a whole lot of Javascript development a few years back, and now my latest project has me doing a lot of it again. Somewhere along the line, the Javascript keyword debugger was introduced (I just tried to look it up to give you a link, but I’m coming up dry… sometimes I just can’t talk Google into giving me what I want).

In a nutshell, the debugger keyword, when hit by an executing script within your browser, will fire up a Javascript debugger, if you have one. On a Windows machine Microsoft Visual Studio 6 and Microsoft Visual Studio .NET will both offer to provide debugging services for your scripts if you have them installed.

In IE, you need to be sure to go to Tools/Internet Options from the menu and choose Advanced, then find the option that says Disable Script Debugging and clear the checkmark. For some reason, after I restart my computer, IE always checks that box again (I haven’t found a way to make it sticky), so I have to clear it every day that I want to do Javascript debugging. This isn’t so bad, though, because if you leave it enabled, IE will offer to let you debug every single buggy script you run across in your surfing, and that can be a real hassle.

Anyway, it’s this simple to use:

<script language="Javascript">
  var x = "This is a string value";
  debugger;
  x = "This value just changed";
</script>

If you run this script in your browser, when it hits the debugger keyword, IE will offer to let you debug the script. Tell it yes, then choose the debugger you wish to use. From there you can step through the code, set watch points and additional break points, and set and examine variable contents. It’s a whole lot easier than using a bunch of alerts and document writes.

There is apparently another debugging tool you can get to run under Mozilla or Netscape on Linux. Here’s where to go to get the Venkman debugger for Mozilla. I haven’t tried it yet, so I don’t know how well it works, but it looks pretty good. More information is available here.