I have a form with two input text fields. The datalist for the second field needs to be populated when the first field has a value. I have everything working as I want except I can't work out how to fire the ajax call when the first field loses focus (I have put in a link I can click to test everything else is working.)
org.rb
class Org < ApplicationRecord
has_many: competitions
end
_form.html.haml
.field
= f.label "Competition:"
League:
= text_field_tag :org, @match.org&.name, list: "orgs", size: 60 # onblur: ?
Division:
= text_field_tag :competition, @match.competition&.name, list: "comps", size: 30
%datalist#orgs
= options_for_select Org.all.map(&:name).sort
%datalist#comps
= render "comps"
_comps.html.haml
= options_for_select @comps.map(&:name).sort
controller
def comps
org = Org.find_from_identifier(params[:org])
@comps = org&.competitions || []
respond_to do |format|
format.js
end
end
comps.js.erb
comps = document.getElementById("comps")
comps.innerHTML = "<%= j render "comps" %>"
If I put this line into the form everything works as I expect when I click it:
= link_to 'test', update_comps_path(org: 'scottishfootballleague'), remote: true
(Routes.rb has get 'matches/comps', to: "matches#comps", as: :update_comps in it.)
So my question is how do I do what that link does when the first input field loses focus?
I tried putting onblur: 'updateComps()' into the field and using
:javascript
function updateComps() {
var org = document.getElementById("org").value
fetch("/matches/comps?org=" + org )
}
This works in the sense that the call gets made at the right time but I'm missing whatever magic data-remote: true attaches to the link to make it an ajax call that works in the rails world. Am I missing a Rails helper? Or do I need to instruct fetch() with what to do with the js that gets returned?
Edit: I've got as far as working out that the response to the fetch consists of the javascript I expect, and which presumably needs to be executed. I've tried this:
:javascript
function updateComps() {
var org = document.getElementById("org").value
fetch("/matches/comps?org=" + org,
{ credentials: "include" })
.then(response => {
eval(response.text());
})
}
There are two problems with this. 1) it doesn't work 2) this doesn't seem very rails-like.
Update (with an answer)
I got the fetch approach working and executing the server generated js:
function updateComps() {
var org = document.getElementById("org").value
fetch("/matches/comps.js?org=" + org,
{ credentials: "include" })
.then(response => response.text())
.then(text => {
eval(text)
})
}
I'm still not at all sure what the "Rails way" of doing this is. Rails.ajax() seems to have been removed (or is only available 'internally') according to some github discussions.
Simplest hack is hide(
display:none) your test link and fireclickonblurof first field.Rails way of doing is user
Rails.ajaxso yourupdateCompswill looks like.Rest of the code for controller and js template will be reused.