1
\$\begingroup\$

I have a Rails app where I'm trying to select a list of facilities based on what region is selected in a form. So far, I've implemented group_collection_select to do this as well as a bit of CoffeeScript.

It works when creating a new record and selecting a region. The behavior being to only show facilities listed for the selected region. What does not work is when editing a record, selecting the facilities shows all of the facilities grouped by region instead of constraining the facilities to the selected region.

If I select another region and then select the original reason, the proper list of facilities show up.

I'd like to learn how to refactor the CoffeeScript to where when editing the record the function is fired both on load and on change.

Here's what my code looks like:

calls.js.coffee

jQuery ->
  facilities = $('#call_transfer_from_id').html()

  $('#call_region_id').change ->
    region = $('#call_region_id :selected').text()
    options = $(facilities).filter("optgroup[label=#{region}]").html()

    if options
      $('#call_transfer_from_id').html(options)   
    else
      $('#call_transfer_from_id').empty()

region.rb

has_many :facilities

facility.rb

attr_accessible :region_id
belongs_to :region

_form.html.erb excerpt

 <%= f.label :region %>
  <%= f.collection_select(:region_id, Region.all, :id, :area, {:include_blank => true}, {:class => 'select', required: true}) %>
  <%= f.label :Transfer_From %>
  <%= f.grouped_collection_select :transfer_from_id, Region.order(:area), :active_facilities, :area, :id, :facility_name, {include_blank: true}, class: 'select' %>

If my question and examples are not clear, please let me know and I'll be happy to edit.

\$\endgroup\$
1
\$\begingroup\$

This is borderline Code Review material, since the code doesn't work as intended. It's not the same thing as "broken", because it does run, but what you're asking for is more or less a new feature.

(I'm also a little unsure of what you're asking, though I think I got it right. This isn't prose review, but you've got some run-on sentences in your question that are nigh impossible to read. Edit: That's been improved now)

Still, I'll give it shot regardless.

First, when you use jQuery, remember to store things you'll use more than once - don't call $(...) again and again for the same selectors.

Second, store a clone of the facilities list element. Not the HTML string. You can just have an element in memory without having to to display it on the page. No need to reduce it a string, and parsing it every time you need something.

Third, I'd use a more precise identifier for the optgroups than the region name. It works, but I'd prefer using an integer ID or something. Unfortunately, grouped_collection_select doesn't have an option to do that (you'd have to write your own version), so I'll skip that here.

I'd extract a function to do the options-setting

$ -> # on DOM ready

  # Grab the elements we'll need
  facilitySelect = $ "#call_transfer_from_id"
  regionSelect = $ "#call_region_id"

  # Make an in-memory clone of the facilities.
  # We'll use this as out "master list"
  facilitiesCopy = facilitySelect.clone()

  # A simple helper function to set the facility select's option
  # to match those in a named optgroup (again, we're cloing elments)
  setFacilityOptionsForSelectedRegion = ->
    region = regionSelect.val()
    options = facilitiesCopy.find("optgroup[label='#{region}'] option").clone()
    facilitySelect.empty().append options

  # Call the function on region change
  regionSelect.on "change", setFacilityOptionsForSelectedRegion

  # and also just call it now that the page has loaded
  setFacilityOptionsForSelectedRegion()

I think that should work.

Edit: Here's a demo

\$\endgroup\$
  • \$\begingroup\$ Thanks for your advice and code example. Unfortunately when I tried using this the transfer_from_id group_collection_select no longer works and there are no facilities available to select. Even when changing region there are no facilities available at all. Should I move this question to SO instead since as you mentioned it's more of a feature than truly broken? Whatever you think is best. And again I appreciate your help and effort. :) \$\endgroup\$ – nulltek Sep 1 '14 at 16:43
  • \$\begingroup\$ @cz3ch Well, if it's more broken now, then yeah, try SO :) But as far as I can tell, the jsfiddle demo works OK, so I can't tell you what goes wrong \$\endgroup\$ – Flambino Sep 1 '14 at 16:49
  • \$\begingroup\$ The jsfiddle demo definitely works, so maybe it's something else in my form that is causing problems. I'll try to work through your example code and see what I can do to make it work. SO is a last resort :) I also tidied up the question so it's more readable. \$\endgroup\$ – nulltek Sep 1 '14 at 16:58
  • \$\begingroup\$ Btw, here's the question posted to SO and we came up with a working answer: CoffeeScript to select form field dynamically on change and on load \$\endgroup\$ – nulltek Sep 12 '14 at 15:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.