Prototype

Rails' observe_field with :on - Rails 2.0

In a previous post I showed how to get around a bug in Prototype that was ignoring the "on" parameter of the observe_field function. The solution I originally posted no longer works with the latest version of Rails and Prototype. Although the documentation for observe_field received a facelift, somehow the Rails team still missed the fact that the :on function doesn't work with the current version of Prototype. Or maybe its the Prototype guys we should be after here. :-)

The new fix requires a change to both prototype.js and a small Rails core update.

I will start with the update to prototype.js. Search for Abstract.EventObserver (around line 3632 in my version). That should now read

Abstract.EventObserver = Class.create({
  initialize: function(element, callback, trigger) {
    this.element  = $(element);
    this.callback = callback;
    this.trigger = trigger;

    this.lastValue = this.getValue();
    if (this.element.tagName.toLowerCase() == 'form')
      this.registerFormCallbacks();
    else
      this.registerCallback(this.element, this.trigger);
  },

  onElementEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  },

  registerFormCallbacks: function() {

Rails' observe_field with :function and :on

I've been fiddling with the observe_field element in Rails using the :function and :on parameters. Basically, I simply wanted to execute some javascript when the onkeyup event fired for a text box. The Rails Documentation lead me to the two parameters that I needed:

  • :function, Instead of making a remote call to a URL, you can specify a JavaScript function to be called.
  • :on, Specifies which event handler to observe. By default, it's set to "changed" for text fields and text areas and "click" for radio buttons and checkboxes. Use this parameter to change the watched event to whatever you want e.g. "blur", "focus", etc..

However, the :on parameter didn't appear to work, and after some further inspection of the Prototype code, I found that the parameter that the Rails code was generating wasn't even being used in Prototype.js.

So, I've modified the Prototype code slightly, to make things work. Here are my changes.

Abstract.EventObserver = function() {}
Abstract.EventObserver.prototype = {
  initialize: function() {
    this.element  = $(arguments[0]);
    this.callback = arguments[1];
    this.trigger  = arguments[2];

    this.lastValue = this.getValue();
    if (this.element.tagName.toLowerCase() == 'form')