Marcelo Risoli
Marcelo Risoli

Reputation: 802

Cocoon callbacks after form reload

I am creating a form where a user can add many nested questions, and each question can have many nested answers, other fields have ActiveRecord validators and when they fail, the page gets reloaded, the inserted fields are still there.

All callbacks(such as cocoon:before-insert) are not reloaded, for instance a change handler of a dropdown on an inserted object

What can I do to make these callbacks be respected if the page is reloaded on a server-side validator fail?

On another note, what would be, code-quality wise, the best way to add handlers created inside a cocoon callback to nested objects built when the new method on the controller is called(i.e. objects which are not affected by after-insert/before-insert callbacks)?

Here's some sample coffeescript code for clarification:

$(document).ready ->
  $('#questions').on("cocoon:after-insert", (e, added_question) ->
    added_question.find('#type').change ->
      if $(this).val() is "1"
        added_question.find("#answers").hide()
      else
        added_question.find("#answers").show()

EDIT: changed question since removal problem was a lack of a proper wrapper-class

EDIT #2: added sample code

Upvotes: 1

Views: 1748

Answers (1)

nathanvda
nathanvda

Reputation: 50057

When using rails4, you are using turbolinks, and you can no longer rely on the document.ready event, instead you should listen to the page:change event.

So your code would become:

$(window).bind 'page:change', () ->
  $('#questions').on("cocoon:after-insert", (e, added_question) ->
    added_question.find('#type').change ->
      if $(this).val() is "1"
        added_question.find("#answers").hide()
      else
        added_question.find("#answers").show()

alternatively you could write $(document).on 'page:change', () -> ... which is imho identical.

[UPDATE: alternative solution]

I had not really read the event handler :) A few remarks:

  • you might need to try with before-insert. That might work.
  • secondly, you are using an id #type, but there will be more than one a page? That is asking for trouble :) If you are getting more than one, use a class. Also, use a more descriptive name.

There is a simpler solution: jquery can bind dynamically, so you can write

$('#questions').on 'change', '.question-type', () -> 
  var this = $(this)
  var question = $(this).parent('.your-question-class')
  question.toggle()

Not sure if you really need to check for the value, just toggle the visibility?

This code is of course not tested, but I hope you get the gis of it. Look up the jquery on handler, it allows to catch events with a selector. So in this case, any change event inside the #questions div, on an element with class question-type (instead of your incorrect #type id) will be handled by this handler. It will by dynamic, since it is attached to the container element. So if questions are added or removed, it is still valid.

Upvotes: 1

Related Questions