Skip to content

Better Edit in place (editable.js)

nakajima edited this page Sep 12, 2010 · 9 revisions

Requirements: event_delegation.js

View the source

The better edit in place script makes it easy to create AJAX edit-in-place fields in a RESTful Rails app. Note that if your approach isn’t RESTful, then this script won’t do much for you.

To make an element editable, give it the class name editable. Specify the element’s resource url as the element’s rel attribute, then give it an id attribute that contains the name of the record’s model, as well as the attribute to be edited. You can also add the record’s id as well, so as not to have multiple elements with the same id in the same page. All in, it should look something like this:

<div class="editable" id="list_name_1" rel="/lists/1">This is a list name</div>

When the element is clicked, it will be hidden, and an input will appear that will allow the user to change the field. You must have an appropriate respond_to set in your controller that renders the record as a JSON response:

respond_to do |format| format.html # Whatever format.js { render :json => @list } end

Simple Rails Helper

If you’re using Rails, it’s pretty easy to create a view helper to make things even easier:

# In your application_helper.rb
def edit_in_place_for(record, field, options={})
options[:tag] ||= :div
options[:url] ||= url_for(record)
options[:id] ||= “#{dom_id(record)}_#{field}”
content_tag options[:tag], record.send(field), :class => ‘editable’, :rel => options[:url], :id => options[:id]
end
# In your view
edit_in_place_for(@list, :name)

The options are pretty self explanatory. The :tag option let’s you specify what kind of HTML tag you want the editable to be, the :url option let’s you specify a different URL than Rails would ordinarily assume, which is useful for nested routes, where you’d pass something like this:

edit_in_place(comment, :body, :url => url_for(post, @comment))

If you want more power, there’s another option.

Better Rails Helper

This helper allows you to pass the resource to be updated with an array like: [@post, @comment], as is the Rails convention. It also allows you to pass whatever additional HTML attributes you want as options.

  def edit_in_place_for(resource, field, options={})
    # Get record to be edited. If resource is an array, pull it out.    
    record = resource.is_a?(Array) ? resource.last : resource

    options[:id]  ||= "#{dom_id(record)}_#{field}"
    options[:tag] ||= :div
    options[:url] ||= url_for(resource)
    options[:rel] = options.delete(:url)

    classes = options[:class].try(:split, ' ') || []
    classes << 'editable'
    options[:class] = classes.uniq.join(' ')

    content_tag(options[:tag], record.send(field), options)
  end

Using the advanced helper, the above Post/Comment example would look like this:

edit_in_place([@post, @comment], :body)

That’s much nicer if you ask me.

So that should be it. Let me know if it’s not.