Search code examples
javascriptnested-formscocoon-gem

How to write a neat JS if else statement to dynamically add a nested Rails simple_form via Cocoon?


I am building a nested simple_form_for in rails using cocoon to dynamically add and remove nested elements. The main model object is a quote and a quote has many employees. I've reached the limit of my amateur code skills and would like some guidance on writing a neat js script so to achieve the following:

  • if nested_object.count <= 2 then remove_empee_link.hide
  • if nested_object.count > 2 then remove_empee_link.show, but not on the first two nested_objects.

  • if nested_object.count > 10 then add_empee_link.hide, otherwise always add_empee_link.show

Adapted from a really helpful post here courtesy of @nathanvda I've got to here;

$(document).ready(function() {
   function check_to_hide_or_show_add_empee_link() {
     if ($('#empee-form .nested-fields:visible').length == 5) {
       $('#empee-form .links a').hide();
     } else {
       $('#empee-form .links a').show();
     }
   }

   $('#empee-form').on('cocoon:after-insert', function() {
     check_to_hide_or_show_add_empee_link();
   });

   $('#empee-form').on('cocoon:after-remove', function() {
     check_to_hide_or_show_add_empee_link();
   });

   check_to_hide_or_show_add_empee_link();     
 });

$(document).ready(function() {
   function check_to_hide_or_show_remove_empee_link() {
     if ($('#empee-form .nested-fields:visible').length <= 2) {
       $('.remove_fields').hide();
     } else {
       $('.remove_fields').show();
     }
   }

   $('#empee-form').on('cocoon:after-insert', function() {
     check_to_hide_or_show_remove_empee_link();
   });

   $('#empee-form').on('cocoon:after-remove', function() {
     check_to_hide_or_show_add_remove_empee_link();
   });

   check_to_hide_or_show_add_remove_empee_link();     
 });

But I'm struggling to put a strategy together on how I can I achieve what I outlined in my biullets above in a neat solution, any guidance would be really appreciated after starting and playing with this for hours. Thanks

The updated code that I've now written, but the behavior is unexpected;

  • If 1, 2 or 3 nested elements on page, then all remove_links hidden.
  • If 4 nested elements on page then 1st, 2nd & 4th have remove_link hidden
  • If 5 nested elements on page then 1st, 2nd & 3rd have remove_link hidden

Intended behaviour, 1st and 2nd remove_links hidden always, anoy others shown:

// Hiding the 1st 'remove employee' link for the first two employee fields.
$(document).ready(function() { 
    function hide_first_and_second_remove_empee_links() {
        var remove_links = $('.remove_fields')
        $(remove_links[0]).hide();
        $(remove_links[1]).hide();
        // $('a.remove_fields:first-child').hide();
        // $('a.remove_fields:nth-child(2)').hide();
    }
    $('#empee-form').on('cocoon:after-insert', function() {
    hide_first_and_second_remove_empee_links();
  });
  $('#empee-form').on('cocoon:before-insert', function() {
    hide_first_and_second_remove_empee_links();
  });
  hide_first_and_second_remove_empee_links();
});

How can this be? There's one method, it collects all .remove_fields' into the remove_links var, then wraps the[0]element of that collection in a jQuery object and callshideon it. Then the same to the1element. That method is called on page ready and then again oncocoon:before-insertandafter-insert. I don't see how the definition of the[0]and the1` elements changes?


Solution

  • Your logic becomes easier when you write:

    • always hide the first two remove links
    • hide the add association link if there are more than 10 employees

    The second is already covered in your answer.

    The first one is actually pretty easy using jquery:

    $('.remove-fields:first-child').hide()
    $('.remove-fields:nth-child(2)').hide()