Does :on => blur works?

Fernando,

What html is actually being generated?

This code is from Rails 1.2.2, but you should be able to track this down in your version if different.

The problem is that the documentation is simply wrong. Let's look at the code:

vendor/rails/actionpack/lib/action_view/helpers/prototype_helper.rb:287:
       def observe_field(field_id, options = {})
         if options[:frequency] && options[:frequency] > 0
           build_observer('Form.Element.Observer', field_id, options)
         else
           build_observer('Form.Element.EventObserver', field_id, options)
         end
       end

line 662:
       def build_observer(klass, name, options = {})
         if options[:with] && !options[:with].include?("=")
           options[:with] = "'#{options[:with]}=' + value"
         else
           options[:with] ||= 'value' if options[:update]
         end

         callback = options[:function] || remote_function(options)
         javascript = "new #{klass}('#{name}', "
         javascript << "#{options[:frequency]}, " if options[:frequency]
         javascript << "function(element, value) {"
         javascript << "#{callback}}"
         javascript << ", '#{options[:on]}'" if options[:on]
         javascript << ")"
         javascript_tag(javascript)
       end

public/javascripts/prototype.js:2124:
Abstract.EventObserver = function() {}
Abstract.EventObserver.prototype = {
   initialize: function(element, callback) {
     this.element = $(element);
     this.callback = callback;

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

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

   registerFormCallbacks: function() {
     Form.getElements(this.element).each(this.registerCallback.bind(this));
   },

   registerCallback: function(element) {
     if (element.type) {
       switch (element.type.toLowerCase()) {
         case 'checkbox':
         case 'radio':
           Event.observe(element, 'click', this.onElementEvent.bind(this));
           break;
         default:
           Event.observe(element, 'change', this.onElementEvent.bind(this));
           break;
       }
     }
   }
}

Form.Element.EventObserver = Class.create();
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
   getValue: function() {
     return Form.Element.getValue(this.element);
   }
});

So a Form.Element.EventObserver has an initialization function from Abstract.EventObserver which looks like this (seen above also):
Abstract.EventObserver.prototype = {
   initialize: function(element, callback) {
     this.element = $(element);
     this.callback = callback;

Notice that it only has two arguments. The third argument added by the build_observer helper is not passed along to the prototype.js function. The actual event is made wholly dependent on:
       switch (element.type.toLowerCase()) {
which is just a fancy way of saying 'change' when that's 'click' for checkboxes and radio buttons.

Now, could the initialize function be changed in Abstract.EventObserver to use the third argument as the event to observe if provided and still fall back to using the element type? Sure. But the moral of this story is that the code itself is the most reliable place to find out how something works -- don't assume that the documentation is always correct.

Of course, these very changes may have already been made in the most recent versions of prototype and Rails, but I'll leave that investigation to the diligent reader. :wink:

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

Hi,

am playing with the blur option myself, and am confused.

Notice that it only has two arguments. The third argument added by
the build_observer helper is not passed along to the prototype.js
function. The actual event is made wholly dependent on:
       switch (element.type.toLowerCase()) {
which is just a fancy way of saying 'change' when that's 'click' for
checkboxes and radio buttons.

Regardless of the rails code analysis, the fact is that if I
put :on=>'blur' into my observer, then I get the blur parameter in the
javascript.

Trouble is it doesn't seem to work!!

When I look at the various references for Prototype (and I am NOT
javascript clever) then I can see no reference to
Form.Element.EventObserver supporting a blur event. It appears to
inherit from Abstract.EventObserver which, it says, only supports
onclick and onchange. Perhaps this is the point that Rob was trying
to make.

Anyway it seems very odd to me that Prototype does not support an on
blur event, and even stranger that Rails implementation suggests that
it does. Maybe someone with understanding of Prototype could clarify,
and hopefully explain how to get to it nicely from Rails. The
alternative I guess, is to use a different JS library, as suggested in
another post, but then it is a case of building our own helpers. Or,
I wonder how difficult it would be to create an on blur event trigger
directly from a Rails helper?

I really do want to do on blur detection on one of my forms. Can
anyone help.

Thanks
Tony