Tuesday, November 27, 2007

Trouble with Ajax.in_place_select_editor for relationships

Using the scriptaculous in place editor controls is cool and very web 2.0, but the examples and documentation are far too simplistic to actually figure out how to do anything useful. So I bought the new book by Pragmatic Programming 'Prototype and Scriptaculous'.

I was very dismayed that on the chapter dealing with Ajax.in_place_select, the example cut short on how to deal with setting up an in place editor for a drop down with a related table. Sure it has simple drop downs, but when you want to relate an 'id' and 'value' back to the control, you are going to have problems because the built in objects to deal with this stuff will not work the way you would expect.

on the text that you would click to activate the control, which will display the initial value, it will display your 'id', not the value. Once you activate the control, it will display the human value, and save back to the server the id selected. Then it will display the id again, not the human value.

I want it to display the human value, not the ID. Thats why we have a relational database in the first place!

To get this to work you have to dive into making helper files to define your own control helpers, and you have to rewrite the way your control

in your application.rb controler

def in_place_related_list_editor_field(object,method, tag_options = {}, in_place_editor_options={})
tag = ::ActionView::Helpers::InstanceTag.new(object, method, self)
tag_options = { :tag => "span",
:id => "#{object}_#{method}_#{tag.object.id}_in_place_editor",
:class => "in_place_editor_field"}.merge!(tag_options)
in_place_editor_options[:url] =
url_for({ :action => "set_#{object}_#{method}", :id => tag.object.id })
jtag="" + tag_options.delete(:show) + ""
return jtag + in_place_collection_editor(tag_options[:id], in_place_editor_options)

def in_place_collection_editor(field_id, options = {})
function = "new Ajax.InPlaceCollectionEditor("
function << "'#{field_id}'," function << "'#{url_for(options[:url])}'," js_options = {} js_options['cancelText'] = %('#{options[:cancel_text]}') if options[:cancel_text] js_options['okText'] = %('#{options[:save_text]}') if options[:save_text] js_options['loadingText'] = %('#{options[:loading_text]}') if options[:loading_text] js_options['savingText'] = %('#{options[:saving_text]}') if options[:saving_text] js_options['rows'] = options[:rows] if options[:rows] js_options['cols'] = options[:cols] if options[:cols] js_options['size'] = options[:size] if options[:size] js_options['externalControl'] = "'#{options [:external_control]}'" if options[:external_control] js_options['loadTextURL'] = "'#{url_for(options[:load_text_url])}'" if options[:load_text_url] js_options['ajaxOptions'] = options[:options] if options[:options] js_options['evalScripts'] = options[:script] if options[:script] js_options['callback'] = "function(form) { return #{options[:with]} }" if options[:with] js_options['clickToEditText'] = %('#{options[:click_to_edit_text]}') if options[:click_to_edit_text] collection = options[:select_options].inject([]) do options, element options << "[ '#{html_escape(element.last.to_s)}', '#{html_escape(element.first.to_s)}']" end js_options['collection'] = "[#{collection.join(',')}]" function << ( options_for_javascript(js_options)) unless js_options.empty? function << ');' javascript_tag(function) end

and in the show:

%= in_place_related_list_editor_field :contact, :contact_type_id, {:show =>@contact.contact_type.name}, :external_control=>'contact_type_id_ext',:select_options => ContactType.to_dropdown(:value => "name",:text => "name"), :rows => 1, :cols =>50 %>

With a greater than before the % above.
<%= in_place_related_list_editor_field :contact, :contact_type_id, {:show =>@contact.contact_type.name}, :external_control=>'contact_type_id_ext',:select_options => ContactType.to_dropdown(:value => "name",:text => "name"), :rows => 1, :cols =>50 %>

No comments: