Skip to content

inkdeep/better-edit-in-place

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Better Edit in Place

The default “in_place_editing” plugin for Rails is disappointing. This is my
solution.

Features

  • Support for nested resources
  • RESTful. Just add a line to your respond_to block to render as JSON.
  • Easy to use outside of Rails. Just add a class name and the path as the
    rel attribute to an element and you’re done.
  • Logic lives in the JavaScript (You may consider this a feature or a flaw. I
    consider it a feature.)
  • Support for text input, text area and select fields
  • Support for foreign key parameters for select fields
  • Customizable. One can set:
    • class for edit element
    • class submit and cancel buttons
    • custom functions to be called on Ajax.Request onLoading and onComplete events
      i.e. to set up a spinner.

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

If you have not installed this plugin using script/plugin install script,
then copy src/editable.js file to your public/javascripts folder.
To load this file with your Rails app simply add the following line to your layout:

<%= javascript_include_tag 'editable' %>

If you’re using the classic way of handling events:

  document.observe('dom:loaded', function(event) {
    Editable.setupAll();
  });

Another solution is to use event delegation:

  document.delegators('click', {
    '.editable': function(element) {
      element.editable();
    }
  });

To make an element editable, give it the class name editable. You can use different
class name, but in this case you need to pass it to Editable.setupAll method
or change CSS selector if you’re using event delegation.

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,
an editable element’s attributes look like this:

<span class="editable" id="list_1_name" rel="/lists/1">…value…</span>

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.

A Rails example:

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

Using it with Rails

If you’re using this plugin in a Rails app, you can use the following view
helper to simplify the markup for your editable element:

edit_in_place(@list, :name)

By default, the edit-in-place tag will be a <span> element. You can override
this using the :tag option:

edit_in_place(@list, :name, :tag => :h1)

Conditional Editing

If you only want to allow editing when certain conditions are met, passing :allow with either true or false will
allow (or not) in place editing.

edit_in_place(@list, :name, :allow => @list.finalized? )

If the non-editable field has an empty or nil value it will render the attribute name:

<i title="This information is missing.">[name]</i>

NOTE
This will only happen if :allow is passed false and the attribute returns true when blank? is called
on it.

When editable attributes have no value the in place editor will have a default :empty_message :

If name is blank?:

edit_in_place(@list, :name)

Will produce:

<span class="editable" id="list_1_name" rel="/lists/1">[name]</span>

If name is blank? and an :empty_message is set:

edit_in_place(@list, :name, :empty_message => 'enter name')

Will produce:

<span class="editable" id="list_1_name" rel="/lists/1">enter name</span>

Setting :edit_blank to false will render an empty span with an attached in place edit form if the value is blank?.

Nested Resources

Better Edit in Place also works seamlessly with nested resources. Just pass
in the resources as an array. This will update an item’s name attribute:

edit_in_place([@list, @item], :name)

The list_item_path will be determined automatically. If you wish to
pass a different URL in, you can do that as well:

edit_in_place([@list, @item], :name, :url => weird_item_path(@item))

If you’re using a newer version of Rails…

You might need to tell ActiveRecord not to include the root while serializing
to JSON. To do so, put this line in an initializer, or environment.rb:

ActiveRecord::Base.include_root_in_json = false

List of Rails configuration options:

:id
:tag
:url
:rel
:edit_blank
:empty_message
:allow

Customizations

Input types

By default input text element is used. To change it to text area, check box, or select, you need to set
editField type:

  document.delegators('click', {
    '.editable': function(element) {
      element.editable({
        editField: {'type': 'textarea'} // or 'select', 'checkbox'
      });
    }
  });

The checkbox behaves the same as a select in that when it is changed the value is updated without the need to submit.

Class names

Edit element class name can also be set:

    element.editable({
      editField: {
        'type': 'textarea',
        'class': 'editable-input'
      }
    });

Class name can also be set for submit and cancel buttons:

    element.editable({
      submitButtonClass: 'editable-submit',
      cancelButtonClass: 'editable-cancel'
    });

Select box options

For select elements you need to specify possible options:

    element.editable({
      editField: {
        'type': 'select',
        'options': [["black", "1"], ["gray", "2"], ["white", "3"]]
      }
    });

To load data directly from Rails, you can use to_json method:

    element.editable({
      editField: {
        'type': 'select',
        'options': <%= Colors.all.map{|c| [c.name, c.id.to_s]}.to_json %>
      }
    });

Foreign keys (only for select boxes)

If edited attribute is a foreign key, you need to explicitly specify it:

    element.editable({
      editField: {
        'type': 'select',
        'options': <%= Author.all.map{|c| [c.name, c.id.to_s]}.to_json %>,
        'foreignKey': true
      }
    });

When using Rails helper, you need to refer to the actual object, instead of the foreign key:

edit_in_place(@post, :author)

You also need to set #to_s method on the associated model i.e.

   class Author < ActiveRecord::Base
     def to_s
       name
     end
   end

Ajax.Request callbacks

You can set custom callbacks for Ajax.Request onLoading and onComplete events:

    element.editable({
      onLoading: function() {alert("Loading...")};
      onComplete: function() {alert("Request completed")};
    });

After save callbacks

Custom functions can be fired after onComplete finishes, allowing for further page manipulation.

    element.editable({
        editField: {
          type: 'checkbox'
        },
        afterSave : function (edited) {
          if (edited.element) edited.element.toggleClassName('true').toggleClassName('false');
        }
      });

List of javascript configurable options.

Configurable options:

option default
editField.type ‘input’
fieldSize ‘30×5’ (only used with text_field and text_area input types)
submitButtonClass inplace-submit
cancelButtonClass inplace-cancel
saveText Save
cancelText Cancel
onLoading Prototype.emptyFunction
onComplete Prototype.emptyFunction
afterSave false (can be passed a function to act on updated element or page )

TODO

  • Escape key should cancel (simple event handler)
  • Maybe some more options (but not too many)
  • Instead of adding .json to URL, set proper content-type
  • Clean up fieldSize setting handling
  • Figure out how to have inline elements not collapse and reflow page when edit
    form is absolute positioned and/or is larger than containing element.

Copyright © 2008 Pat Nakajima

About

Easy editing in place for RESTful web apps.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 93.5%
  • Ruby 6.5%