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