Search code examples
javascriptruby-on-railsujs

div show/hide UJS, remember state when form contains errors and render(action: :new) occurs


Using 'form_for' to build Person for 'People' model. Here is UJS to show and hide div on checkbox click.

people.js

  window.onload = function() {
    $('#is_student_chkbx').click(function() {
      return $('#student_properties').toggle();
    });
    return true;
  };

genrated page people/new

...
<input id="is_student_chkbx" name="person[role_attributes][is_student]" type="checkbox" value="true" />

<div id='student_properties' style='display:none;'>
  <p>Test text</p>
</div>
...

people_controller.rb

class PeopleController < ApplicationController
  def new
    @person = Person.new
    @person.build_role
  end

  def create
    @person = Person.new(params[:person])
    ...
    @person.save ? redirect_to(person_path(@person)) : render(action: :new)
  end
end

But there is a problem. When form contains errors (like "Name can't be blank" because of validation in the model), render(action: :new) occurs but 'student_properties' div is not visible even if 'is_student_chkbx' is checked. So when I click 'is_student_chkbx' again -> checkbox is not checked but 'student_properties' div shows up.

So how to remember state of this div?

I tried to add if ($('#is_student_chkbx').is(':checked')) {$('#student_properties').show();} to window.onload but it didn't happend on render(action: :new)


Solution

  • To get it working, I used (thanks to rb512, who pointed my attention):

    <div id='student_properties' style='display:<%= @person.role.is_student ? 'block' : 'none' %>;'>
    

    Instead of:

    <div id='student_properties' style='display:none;'>
    

    But the better way is to use CSS Class:

    .hidden {
      display:none;
    }
    

    Then target string will look like:

    <div class='your_other_class <%= 'hidden' unless @person.role.is_student %>' id='student_properties'>