Reputation: 319
I have no idea if is it possible to do.
I have form for company Profile. Some data (17 fields in company_data partial) can be fetch using tax_number. Is is possible to replace turbo_frame 'profile_company_data' with controler turbo_stream.replace?
How to get f (form_builder object) in turbo_stream - it is needed to render partial in turbo response.
= form_with model: @profile, url: profile_path do |f|
.columns
.column.is-4
.field
=f.label :tax_number, 'Tax number', class: 'label is-required'
.control
= f.text_field :tax_number, class: 'input', maxlength: "13"
.column.is-2
.button.is-primary{onClick -> 'fetch_company_data()'} Read company Data
= turbo_frame_tag 'profile_company_data' do
= render 'company_data', f: f
.block
= f.fields_for :main_address do |addr|
= render 'address_fields', f: addr
I've tried render this snippet inside turbo response. It works but it creates nested form tag with new csrf-token.
= form_with model: @profile, url: profile_path do |f|
= render 'company_data', f: f
Upvotes: 3
Views: 400
Reputation: 369
I went with a modified version of Alex's answer.
def something
# TODO: @profile =
respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.update(
:profile_company_data, partial: "company_data", locals: {f: profile_form_object}
)
end
end
end
def profile_form_object
helpers.fields model: @profile do |f|
return f
end
end
This way I can reuse the profile_form_object in other controller actions.
# ledger_items/_form.html.haml
= form_with model: ledger_item, do |f|
= f.label :account_name, class: "form-label"
= f.text_field :account_name, class: "form-control"
= f.label :expense_code_id, class: "form-label"
= render "ledger_items/expense_code_field", f: f
I only needed to replace a select box to change the expense_code options, so I put that field in it's own partial.
# ledger_items/_expense_code_field.html.haml
= f.select :expense_code_id,
grouped_options_for_select(ExpenseCategory.select_code_options(current_company),
f.object.expense_code_id), { include_blank: '- Please select -' },
{ id: 'ledger_item_expense_code_id', class: "form-select"}
Then in my controller
# some_action
format.turbo_stream do
render turbo_stream: [
turbo_stream.replace("ledger_item_expense_code_id",
partial: "ledger_items/expense_code_field",
locals: { current_company: current_company, f: ledger_item_form_object }
)
]
end
def ledger_item_form_object
helpers.fields model: @ledger_item do |f|
return f
end
end
Notice I didn't need to use a turbo_frame_tag to replace the select box, just the select box ID.
Upvotes: 0
Reputation: 281
You can use the fields
method instead of form_with
def add_nested_field
@profile = current_user.profile
end
// add_nested_field.turbo_stream.erb
<%= turbo_stream.update("profile_company_data") do %>
<%= fields model: @profile do |f| %>
<%= render 'company_data', f: f %>
<% end %>
<% end %>
This will generate the fields with correct naming for params but not add the csrf token, etc.. that form_with does.
Upvotes: 2
Reputation: 30036
You can do it straight from controller:
def something
# TODO: @profile =
respond_to do |format|
format.turbo_stream do
helpers.fields model: @profile do |f|
render turbo_stream: turbo_stream.update(
:profile_company_data, partial: "company_data", locals: {f:}
)
end
end
end
end
onClick -> 'fetch_company_data()'
that will need to be a TURBO_STREAM request: https://stackoverflow.com/a/75579188/207090
Do you actually need turbo_frame_tag
there?
Note that replace
will replace the <turbo-frame>
with whatever is rendered by the partial. But you probably want to keep it.
Upvotes: 2