Tuesday, April 17, 2012

Cocoon : link_to_remove_association : confirm box

Really happy when used the nathanvda/cocoon for adding nested model records.
This makes life easy. But only thing I missed was confirmation message.

We can actually add html_options to the method, but because of "remove_fields" class, this actually removes/ hides the fields on-click of the link.
So adding confirmation from html option was no use.

So for overriding, I added the following method in application_helper.rb. But you can also add it in new view helper class in lib and include it in application helper(just to keep it separate).
# Adding confirm message for association remove links.
# Original : f.hidden_field(:_destroy) + link_to(name, '#', :class => "remove_fields #{is_dynamic ? 'dynamic' : 'existing'}")
# Cocoon : ViewHelpers : link_to_remove_association
# link_to_remove_association(name, f, args={})
# name : to be displayed for link.
# f : form object
# args : defaults set to empty hash.
#        this holds the html options like onClick.
#        e.g : link_to_remove_association "name", f, { :onClick => "onclick();", onBlur => "onblur();" }
# extra_class : If no html options are passed from the view it will append 
#               the class to the class attribute of the link.
#               This will call the original functionality
# option_class : If class key added in view for styling purpose, this will add it to the args
# is_dynamic : is as per the original functionality. Lets us know if the records is new or existing.
def link_to_remove_association(name, f, args={})
  extra_class = (args.has_key?(:onclick) || args.has_key?(:onClick)) ? nil : "remove_fields"
  is_dynamic = f.object.new_record? ? 'dynamic' : 'existing'
  option_class = args.has_key?(:class) ? args[:class] : nil

  args.merge!({:class => "#{extra_class} #{is_dynamic} #{option_class}"})
  f.hidden_field(:_destroy) + link_to(name, '#this', args)
end
This worked out smoothly.
Now if I dont pass any option it will actually append the remove_fields class to the class option of the link.
This will run the original functionality of cocoon.
This is working for me as required functionality.

Now in javascript I have added function for confirming the removal.
So added
/* confirm_for_remove_record(field, confirm_message)
*  record : The whole row of the current clicked field.
*  record_input : method delete input.
*  class_name : added div class name for appending dialog.
*/
function confirm_for_remove_record(f, message, max_records){
  var record = $(f).closest(".nested-fields");  
  var record_input = $(f).prev();
  var class_name = "." + record_input.attr("id")

  /* Appending extra div for dialog box holder */
  $(f).parent().append( "<div class=" + record_input.attr('id') + ">" + message + "</div>" )
  
  /* Adding dialog box functionality to newly added div 
  *  If field is dynamic it will delete the entire div 
  *  else it will just hide and remove the class name ".nested_fields" from the div class attribute.
  *  If less than max_length then enable add_a_record link by removing the class "disable" from the anchor tag.
  */
  $( class_name ).dialog({
    draggable : false,
    resizable : false,
    modal : true,
    buttons : {
      "Remove" : function() {
        $( class_name ).dialog( "close" );
        $(record_input).val(1);
        
        if($(f).hasClass("dynamic")){
          $(record).remove();  
        }else{
          $(record).hide();
          $(record).removeClass("nested-fields");
        }

        if($(".nested-fields").length < 15 ){
          $("#add_a_record").removeClass("disabled");
        }        
        
      },
      "Don't Remove" : function() {
        $( class_name ).dialog( "close" );
      }
    }
  }).dialog( "open" );
}
And in view
link_to_remove_association "X", f, { :onclick => "confirm_for_remove_record(this, '#{t :confirm_for_remove_record}', 10)" }

No comments:

Post a Comment