I am looking for a way to change the options in a rails form.select field through JavaScript based on the selected option for another select field.
The way I was trying to do this before was by using two separate fields with the same object and different sets of options, like so:
<%= form_with(model: my_model) do |form| %>
<div class="form-floating" id="input">
<%= form.select :input, ['a', 'b'], { }, class: "form-control" %>
<%= form.label :input %>
</div>
<div class="form-floating" id="output1">
<%= form.select :output, ['c', 'd'], { }, class: "form-control" %>
<%= form.label :output %>
</div>
<div class="form-floating" id="output2">
<%= form.select :output, ['e', 'f'], { }, class: "form-control" %>
<%= form.label :output %>
</div>
<script>
function onChange() {
var selected = $('#input option:selected').text()
if (selected == 'a') {
$('#output1').show()
$('#output2').hide()
}
if (selected == 'b') {
$('#output1').hide()
$('#output2').show()
}
}
$('#input').change(onChange)
$(window).on("turbolinks:load", onChange)
</script>
<%= form.submit class: "btn" %>
<% end %>
The problem with this method is that the :output field is created twice and only the last one (with id="output2") is submitted, so I'm now looking for a way to change the select options in the onChange() method for a single output form.select field.
Any help with this issue or an alternative solution would be greatly appreciated, cheers.
Solved the problem, posting it here for anyone else having this problem. Basically I abandoned the rails form helper in favour of building up the html string using tags, something like this:
function replaceHTML() {
var newHTML = '<select class="form-control" name="output" id="output">'
var selection = $('#input option:selected').text()
var options = selection == 'a' ? ['c', 'd'] : ['e', 'f']
for (let i = 0; i < options.length; i++) {
newHTML += '<option value=' + options[i] + '>' + options[i] + '</option>'
}
newHTML += '</select><label for="output">Output</label>'
$('#output').html(newHTML)
}
Short answer: Use $('#output-')prop('disabled', true); instead of .hide().
Long answer:
According to the JQuery docs, .hide() doesn't actually disable the input, it just hides it with CSS. Same with .show() it looks like. So you need to be using a different method for this. More on that in a second.
Second, the reason that only the second select box is being sent through, output2, is probably because they are both set up to be <%= form.select :output %>. According to the Rails docs, under the hood, Rails is setting both of these inputs up like this:
<select name="output"></select>
Since you have two select boxes with the same name attribute, they're overwriting each other. This is again because you're using .hide() and .show(), so they're not actually being disabled.
I think this would work in your scenario. Try using $("output").prop('disabled', true); like so:
function onChange() {
var selected = $('#input option:selected').text()
if (selected == 'a') {
$('#output1').show()
$('#output2').prop('disabled', true);
}
if (selected == 'b') {
$('#output1').prop('disabled', true);
$('#output2').show()
}
}
If you're using JQuery Version < 1.5, you can use $("input").attr('disabled','disabled'); according to this Stack Overflow Answer.