Showing posts with label inplace. Show all posts
Showing posts with label inplace. Show all posts

Tuesday, August 9, 2011

How to create scriptaculous ajax inplace editor fields in Rails3 with validation

First, we should do our html view in app/views/ips/index.html:

<div id="ips_table_div">
<%= render "ips_table" %>
</div>

Then, we create the table and the javascript code in our partial view (app/views/ips/_ips_table.html.erb).

<table cellpadding="10"><tbody>

<% unless @ips.nil? %>

		<tr>

			<td id="ip_new_ip_td_div">
				<%= form_tag url_for(:controller => :ips,
							:action	=> :create_ip),
						:remote => true,
						:id 	=> "new_ip" %>
					
						<%= text_field_tag "ip" %>
						<%= submit_tag t(:add_button, :scope => [:application]), :id => "new_ip_submit" %>
				</form>
			</td>

			<td>
			</td>

		</tr>

	<% @ips.each do |ip| %>
		<tr>

			<td id="ip_ip_td_div_<%=ip.id %>">
				<div id="ip_ip_text_div_<%=ip.id %>"><%= ip.ip %></div>
			</td>

			<td>
				<%= link_to t(:delete_link, :scope => [:application]),
 								url_for(:controller => :ips,
									:action	=> :delete_ip,
									:id 	=> ip.id),
								:remote => true,
								:confirm => t(:ip_delete_confirm, :scope => [:application])%>
			</td>

		</tr>
	<% end %>

<% end %>

</tbody></table>

<script type="text/javascript">
var ip_validate_background_color_error = "#fff999";
var ip_validate_border_color_error = "#f80000";
var ip_validate_background_color = "#ffffff";
var ip_validate_border_color = "#999999";

var ipModifyFormOptions= $H({
		cancelText:'<%=t :cancel_link, :scope => [:application] %>',
		okText: 'ok',
		savingText: '<%=t :saving_text, :scope => [:application] %>',
		loadingText: '<%=t :loading_text, :scope => [:application] %>',
		clickToEditText: '<%=t :click_to_edit_text, :scope => [:application] %>',
		
});

<% unless @ips.nil? %>

Form.findFirstElement('new_ip').style.borderColor = ip_validate_border_color;
Form.findFirstElement('new_ip').style.backgroundColor = ip_validate_background_color;
Form.findFirstElement('new_ip').setAttribute("onkeypress","return input_filter_exact(event, 'ip')");
$('new_ip_submit').disabled=true;
new Form.Observer('new_ip', 0.3, function(form, value) {
		if(validateIpAddress(Form.findFirstElement('new_ip').value, false) == true) {
				Form.findFirstElement('new_ip').style.borderColor = ip_validate_border_color;
				Form.findFirstElement('new_ip').style.backgroundColor = ip_validate_background_color;
				$('new_ip_submit').disabled=false;
		}	else {
				Form.findFirstElement('new_ip').style.borderColor = ip_validate_border_color_error;
				Form.findFirstElement('new_ip').style.backgroundColor = ip_validate_background_color_error;
				$('new_ip_submit').disabled=true;
		}
});


	<% @ips.each do |ip| %>

new Ajax.InPlaceEditor('ip_ip_text_div_<%=ip.id %>', '<%= url_for :controller => :ips, :action => :modify_ip, :id => ip.id	%>', ipModifyFormOptions.merge({
	formId: 'ip_ip_form_<%=ip.id %>',
	onEnterEditMode: function(form, value) {
			setTimeout(function() {
					Form.findFirstElement('ip_ip_form_<%=ip.id %>').style.borderColor = ip_validate_border_color;
					Form.findFirstElement('ip_ip_form_<%=ip.id %>').style.backgroundColor = ip_validate_background_color;
					Form.findFirstElement('ip_ip_form_<%=ip.id %>').setAttribute("onkeypress","return input_filter_exact(event, 'ip')");
					new Form.Observer('ip_ip_form_<%=ip.id %>', 0.3, function(form, value) {
						if(validateIpAddress(Form.findFirstElement('ip_ip_form_<%=ip.id %>').value, false) == true) {
							Form.findFirstElement('ip_ip_form_<%=ip.id %>').style.borderColor = ip_validate_border_color;
							Form.findFirstElement('ip_ip_form_<%=ip.id %>').style.backgroundColor = ip_validate_background_color;
							$('ip_ip_form_<%=ip.id %>').elements[1].disabled=false;
						}	else {
							Form.findFirstElement('ip_ip_form_<%=ip.id %>').style.borderColor = ip_validate_border_color_error;
							Form.findFirstElement('ip_ip_form_<%=ip.id %>').style.backgroundColor = ip_validate_background_color_error;
							$('ip_ip_form_<%=ip.id %>').elements[1].disabled=true;
						}
				});
			}, 1000);
	}
}).toObject());

	<% end %>

<% end %>
</script>

Then we should make the controller (app/controllers/ips_controller.rb):

respond_to :js, :only => [:delete_ip, :create_ip]
respond_to :html, :except => [:delete_ip, :create_ip]
layout :application, :except => [:delete_ip, :create:ip, :modify_ip]
layout false, :only => [:delete_ip, :create:ip, :modify_ip]

def index
  @ips=Ip.all
  respond_with(@ips)
end

def delete_ip
  Ip.destroy(params[:id])
  # it will returns a javascript code by default, so have to do the
  # app/views/ips/delete_ip.js.erb, what will loads the table completely
 @ips=Ip.all
  respond_with(@ips)
end

def create_ip
  ip=Ip.new(params[:ip]).save
  # it will returns a javascript code, so have to do the
  # app/views/ips/create_ip.js.erb, what will loads the table completely
  @ips=Ip.all
  respond_with(@ips)
end

def modify_ip
  ip=Ip.find(params[:id])
  ip.update_attribute(:ip, params[:value])
  # don't forget some validations here also
  # it will returns a html code, so have to do the
  # app/views/ips/modify_ip.html.erb, what will contains the new text only, or:
  respond_to do |format|
    format.html { render :text => ip.ip }
  end
end

Then we can create returned javascript codes app/views/ips/create_ip.js.erb and delete_ip.js.erb:

  $("ips_table_div").innerHTML='';
  $("ips_table_div").update("<%=escape_javascript(render(:template => "/ips/_ips_table.html.erb", :locals => {:ips => @ips})) %>"); 

Finally we must define javascipt validation functions in public/apllication.js:

function validateIpAddress(value, can_be_empty) {
    if (arguments.length == 1) {
        can_be_empty = false;
    }
    if (can_be_empty == true) {
        if (value == null) {
            return false;
        }
        if (value == "") {
            return true;
        }
    }
    if (value.match(/\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/))
    {
        if (value.length>0 && value.length<256)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false; 
    }
}

function input_filter_exact(e, type) {
    var enabled_chars;    
    switch (type)
        {
            case "ip": enabled_chars="0123456789.";
                                    break;
            default: enabled_chars="-/.,_?[]()!abcdefghijklmnopqrstvuwxyzABCDEFGHIJKLMNOPQRSTVUWXYZ0123456789éáőúűóüöíÉÁŐÚÓÜÖÍ ";
        }
    var key;
  var keychar;
    if (window.event)
        key = window.event.keyCode;
  else if (e)
        key = e.which;
    else
        return true;
    keychar = String.fromCharCode(key);
    if ((key==null) || (key==0) || (key==8) || (key==9) || (key==13) || (key==27) )
        return true;
    else if (((enabled_chars).indexOf(keychar) > -1))
        return true;
    else
    return false;
} 


That's all. Works with Rails 3.0.9, Prototype 1.7 and script.aculo.us v1.8.3