act_as_newbie

Keeping a newbie mindset, at all times.

Client_side_validations and Dynamic Nested Forms

| Comments

Last week I found a little caveat when using the client_side_validations gem with ajax-loaded forms. It didn’t work out of the box.

Digging through the sourcecode I found this comment

rails.validations.js
1
2
3
4
  // Main hook
  // If new forms are dynamically introduced into the DOM the .validate() method
  // must be invoked on that form
  $(function () { $('form[data-validate]').validate(); });

Ok, so I called $("#my-form").validate() on ajax:success and everything was fine! Except it wasn’t =/

The behavior I understood, after banging my head against the wall several times was: if the form was entirely rendered in my ajax call it would validate ok, but if I added some fields inside it dynamically then I’d start getting those nasty validators is not defined errors and everything would go boom!

So how do I add some fields to the form and keep them “validatable”? this issue gave me some insight. And after rummaging the code a little more I found that this gem registers the validators in the window object. This process is done inside the form renderer, and that’s why the full rendered forms worked and adding just some of the fields did not. To accomplish that I created this helper

1
2
3
4
5
6
7
8
9
  def add_dynamic_validators(builders)
    result = ""
    builders.each do |builder|
      builder.object.client_side_validation_hash.each do |validator|
        result += "window[form_id].validators['#{builder.object_name}[#{validator[0]}]'] = #{validator[1].to_json};\n"
      end
    end
    result.html_safe
  end

It recieves an array of form builders and inspect it for the validators added by the gem. Then it prints the resulting instruction within the form partial, inside a function, to which I pass the id of the form that I want to validate.

1
2
3
4
  function update_dynamic_fields(form_id)
  {
    <%= add_dynamic_validators builders %>
  }

Then after the fields (with the script block) were added the to form you can call

1
2
  var $form = $("#my-form");
  update_dynamic_fields($form.attr("id"));

I know this is hacky as hell, but with this I was able to keep using this gem even inside pages with lots of moving parts.

Comments