Simple use case with partial reloading in reaction to onChange

I have a form with a select. Under it, I have a partial initially rendered.
I’d like to get that partial reloaded when the select is changed.

The simplified view :

<%= form_with(model: reminder, html: { "data-controller": "form" }) do |form| %>
    <%= form.select :frequency, Reminder.frequency_options, {}, { "data-form-target": "frequency", "data-action": "change->form#updateFrequencyDescription" } %>

    <%= content_tag :div, id: "frequency_description" do %>
        <%= render partial: "frequency_description", locals: { reminder: reminder } %>
    <% end %>
<% end %>

The Stimulus controller :

export default class extends Controller {
  static targets = ['frequency']

  updateFrequencyDescription() {
    console.log('updateFrequencyDescription')
    fetch(`/reminders/update_form_frequency_description.turbo_stream?frequency=${this.frequencyTarget.value}`)
  }
}

The controller action :

def update_form_frequency_description
    reminder = Reminder.new(frequency: params[:frequency], name: "Fake name") # I set a fake name just to see if it’s updated on the page

    render turbo_stream: turbo_stream.replace("frequency_description", partial: "frequency_description", locals: { reminder: reminder })
end

When changing the value of the select, a request succeeds and gets a “text/vnd.turbo-stream.html; charset=utf-8” response with this content :

<turbo-stream action="replace" target="frequency_description">
<template>
<p class="tag is-success is-light">
     Fake name
  </p>
</template>
</turbo-stream>

That’s what I expected, yey !
But the page does not get updated. I guess I’m misunderstanding something.

It’s not clear to me if the div#frequency_description must be a turbo_frame_tag or not.
Is the response of the fetch call supposed to be auto evaluated by Turbo ?

Thanks.

Is the response of the fetch call supposed to be auto evaluated by Turbo ?

Calls to window.fetch are not evaluated by Turbo. I think making this small change to your Stimulus controller could get things working the way you expect. :thinking:

-fetch(`/reminders/update_form_frequency_description.turbo_stream?frequency=${this.frequencyTarget.value}`)
+Turbo.visit(`/reminders/update_form_frequency_description.turbo_stream?frequency=${this.frequencyTarget.value}`)
3 Likes

Thanks @danott, that’s indeed working :wink:

1 Like

When I do this, the URL changes. What is the best way to prevent that?

I am doing this in a form

onChange:"Turbo.visit(`/sites/index_by_country?country_id=${this.value}`)"

I am refreshing a second select when the first select above changes value.