This is a bit out of topic, but I would like to mention it anyway.
Because of out of order responses, I would suggest to use Stimulus and manually issue and abort fetch requests. I.e. if we need to send a new fetch request and the previous one did not finish yet, then just abort the previous one. This fixes out of order search results.
Back to the original problem. Yesterday I thought that requestSubmit() is the right answer. However, as it was pointed out by @walterdavis, it’s not supported by Safari.
For what it’s worth, I’ve kept rails-ujs to submit forms for now. I’m using it like this:
Rails.fire(form, "submit")
Sure enough, for a form (without a submit button) that’s in a Turbo Frame this does trigger turbo requests.
Now there has been some discussion about keeping rails-ujs, but I’m not sure if this particular function should be on the list (@dhh?). And I’m not even sure if I’m abusing stuff or if Rails.fire is indeed a sure-fire way of getting this to work.
one problem I have is sending updates generated from HTML media element events, so using a form submission is not really an option. Of course I use fetch(); but then I’m handling low level HTML changes in Stimulus. It works, but it could be a lot more elegant if I could use streams.
UPDATE:
I can now confirm that requestSubmit() successfully works with Turbo streams as well.
I like this approach a lot. I realized you could use src in this manner a while after I wrote my original response, but I think this may be better. My only concern would be that it kind of gets into the guts of how frames work.
Would you happen to know how to run a call back after the form submission response is received?
In my particular case, I have something like this. from within my controller, I want to highlight the results which matches the stimulus indexValue. I was thinking that this could easily be done with a callback after the form submission is made and the results are rendered. Any ideas on how this could actually be done?
<div data-controller="somecontroller" data-somecontroller-index-value="1" />
turbo_frame_tag "results"
<form etc />
<li> results etc. </li>
<li> results etc. </li>
end
The issue with turbo:submit-end is that I wish to act on the results after they are added to the dom. I was unable to get turbo:submit-end to do this?
<div data-controller="slideshow" data-slideshow-index-value="1" />
turbo_frame_tag "results"
<form />
<li> results etc. </li>
end
Form is submitted via javascript (i.e. within turbo_frame_tag)
Controller is hit and results are returned.
We want to perform some action on the results that are returned. i.e. a callback after the form submission and after everything’s rendered
I was unable to get turbo:submit-end to work on the rendered response of the form submission. Off the top of your head: is this the expected behaviour?
highlightCurrentSlide(event){
this.slideTargets.forEach((element) => {
// the slideTargets get updated on the form submission
// the highlightCurrentSlide method seems to run before the
// the results of the form submission are rendered.
}, this)
}
Hmm…turbo:submit-end only fires after your controller has responded. So I guess the issue here is the gap between getting that response and the HTML actually being put in the DOM. I wouldn’t expect that gap to be significant, though.
A couple of ideas (I haven’t tested any of them, mind):
The event exposes the FetchResponse via event.detail.fetchResponse (I think). FetchResponse has a responseHTML method that returns a promise. You could make your highlightCurrentSlide method async and on the first line await event.detail.fetchResponse.responseHTML().
Or, failing any of that, there’s probably a solution using MutationObserver and/or maybe giving those slideTargets their own controller (so you could just use connect).