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 page load (when editing) and on change.
Lastly, there are use cases when the transfer_from_id is set to nil/blank and we use a text field called transfer_from_other. Currently if I do not select a facility and fill in transfer_from_other, because of the CoffeeScript loading the facilities in transfer_from_id it will set the transfer_from_id by the first facility in the scope. I'd like to make this to where if no facility is selected, the transfer_from_id is nil so I can use transfer_from_other.
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' %>
<%= f.label :Transfer_From_Other%>
<%= f.text_field :transfer_from_other %>
If my question and examples are not clear, please let me know and I'll be happy to edit.
Regarding updating the select on both page load and on selection change, unless I'm missing something isn't it sufficient to simply break out the select update portion into its own function, that you then call once on page load, and then on each selection change?
jQuery ->
facilities = $('#call_transfer_from_id').html()
update_facilities = ->
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()
$('#call_region_id').change ->
update_facilities()
update_facilities()
Regarding the second part, each time you update the #call_transfer_from_id
select, you will lose the blank option. This second version adds in and selects a blank option each time you select a region:
jQuery ->
facilities = $('#call_transfer_from_id').html()
update_facilities = ->
region = $('#call_region_id :selected').text()
options = $(facilities).filter("optgroup[label=#{region}]").html()
if options
# Set the options
$('#call_transfer_from_id').html(options)
# Add in a blank option at the top
$('#call_transfer_from_id').prepend("<option value=''></option>")
# Ensure that the blank option is selected
$('#call_transfer_from_id option:first').attr("selected", "selected");
else
$('#call_transfer_from_id').empty()
$('#call_region_id').change ->
update_facilities()
update_facilities()
So I've been playing around with this problem and I think I've found a solution that works on both Chrome and Firefox respectively.
jQuery ->
facilities = $('#call_transfer_from_id').html()
update_facilities = ->
region = $('#call_region_id :selected').text()
options = $(facilities).filter("optgroup[label=#{region}]").html()
if options
# Set the options and include a blank option at the top
$('#call_transfer_from_id').html("<option value=''></option>" + options)
# Ensure that the blank option is selected
$('#call_transfer_from_id').attr("selected", "selected")
else
$('#call_transfer_from_id').empty()
$('#call_region_id').change ->
update_facilities()
update_facilities()
I was able to refactor and remove a line of code and set the options and the blank option in one line instead of using prepend. For some reason Firefox didn't like the prepend method. So by calling this line: $('#call_transfer_from_id').html("<option value=''></option>" + options)
I am able to pass the options and insert a blank option at the beginning of the array.
So far I've tested on both Chrome and Firefox and it displays the following behavior.
When creating a new call, facilities are constrained by region, and a blank option is presented in the field for selection. If you enter a transfer_from_other address and leave transfer_from_id nil it retains the nil value.
When editing a call that has transfer_from_other address filled out the transfer_from_id no longer populates with the first facility in the list, instead it lists the blank (nil) option.
When editing a call that has transfer_from_id assigned, it retains the original value of the record and still constrains by region.
Can you look at my code and see if it makes sense. I stumbled upon doing it this way and somehow got it to work. Trying to understand why this works on both browsers versus your answer which only works on Chrome.