Rails 7 using hotwire to replace a form element - ruby-on-rails-7

Context: a form has a collection_select, but without a value that interests the user.
A second form allows to create a new entry that would populate the collection_select with a desired value.
Class Article has_many :tags
The create turbostream does render the object, but the form does not display the change & I suspect it is due to the atomicity of the form. the IDed div tag was tried both outside and inside the form_fields tag to the same neutered effect.
<%= form.fields_for :tags do |tag| %>
<div id='tags'>
<%= f.collection_select(:tag, #tags, :id, :name) %>
</div>
<% end %>
The turbo_stream file tris to replace the target. If f.collection_select is used, this generates an error as rails, handling the snippet does not know of the form's existence. Using select_tag, a tag is rendered and delivered but the div is not refreshed
<%= turbo_stream.replace "tags" do %>
<div class='fade-in-div'>
<%= select_tag :tag, options_from_collection_for_select(#tags, :id, :name) %>
</div>
<% end %>
How can these options for select be updated with hotwire?

Functional answer that does not answer the question:
• the new data needs its own field
• make that an allowed attribute with the relevant accessor atrr_accessor
• process the new value
• update the record
• choose preferred path: redirect or turbo_stream a partial as a replacement of entire form.

Related

Stimulus Reflex drop down with selectize.js

I have a search form for an index page following the tabular demo. It works perfectly. The list I have that I want to filter by is quite long and I wanted to make it searchable so I added selectize.js, that piece also works just fine.
The problem is they don't work together. After selecting an item now it doesn't fire off the call to TabularReflex#search to filter the results.
#app/views/foo.index.html
<%= form_with scope: :search, url: '/search', html: { "data-reflex" =>"debounced:change->TabularReflex#search"} do |f| %>
<%= f.select :foo, options_for_select(#search.foo), {include_blank: 'Select a Foo'}, {class: 'selectize'} %>
<% end %>

Rails: Embed child in submit_tag

I have this form:
= form_tag(path, name: "name") do |f|
= hidden_field_tag "abc", content
= submit_tag "" do
%i.icon.ion-android-sync
As you can see, I am trying to put an Ionicon inside the Form Submit tag.
I've tried a bunch of ways, none of which worked.
With the given example I get an empty button with an approximate width of 3px.
Is it possible to embed a child in a submit_tag? If, how would you go about doing so?
Thanks a lot for each answer!
The short answer is "no". However, you can make a button with type of "submit" that'll do the same thing and allow you to put content in it:
%button{type: "submit"}
%i.icon.ion-android-sync
No the Rails submit helper won't let you do that.
I use a custom submit helper in my app :
# Render a form submit button
# === Params
# +value+:: Value of the input/commit button, used for route constraints
# +text+:: Text for the button
# +:html_options+::
def submit(value=nil, text=nil, html_options={})
text ||= 'Submit'
html_options[:name] ||= 'commit'
html_options[:type] = 'submit'
html_options[:data] ||= {}
html_options[:data][:disable_with] ||= 'Please wait'
html_options[:autocomplete] = "off" # https://github.com/rails/jquery-ujs/issues/357
content_tag(:div, class: 'form-submit-wrapper') do
button_tag(html_options){ block_given? ? yield : text }
end
end
You can just pass whatever HTML you want in a block (sorry this is ERB, I'm not really familiar with HAML)
<%= submit do %>
<i class="icon ion-android-sync"></i>
<% end %>
The first two params are only helpful if you have several submit buttons for your form
<%= submit('preview_action', 'Preview result') do %>
<i class="icon ion-android-sync"></i>
<% end %>
<%= submit('really_do_action', 'Do it for real') do %>
<i class="icon ion-android-sync"></i>
<% end %>

Rails 4 Formatting DateTime field in partial

I'm storing a datetime field in UTC, but the user can enter it in various time zones. I configure the time zones by setting a cookie via JavaScript. Here is my ApplicationController code:
before_filter :set_timezone
def set_timezone
if !cookies["time_zone"].to_s.blank?
Time.zone = cookies["time_zone"].to_s
end
end
I'm storing the times using nested attributes on another controller's form. Here is the partial that renders to fields via simple_form and simple_fields_for, passing in the form as 'f':
<div class="row fieldset">
<div class="col-sm-3">
<%= f.input :day, collection: days, selected: f.object.day %>
</div>
<div class="col-sm-3">
<%= f.input :open, as: :string %>
</div>
<div class="col-sm-3">
<%= f.input :close, as: :string %>
</div>
<div class="col-sm-3">
<%= f.input :_destroy, as: :hidden %>
<%= link_to "remove", '#', class: "remove_fields" %>
</div>
</div>
The time zone conversion is working correctly. I can enter times in the time zone that JavaScript detects, and then it will store them in UTC. It also displays them in the detected time zone, but prints out the full format:
2014-07-22 05:00:00 -0700
I believe the fields are strings by the time they get to the view, and that's why setting the value of the input field to the following doesn't work:
<%= f.input :close, as: :string, input_html: { value: f.object.close.to_s(:short) } %>
I'm just testing the 'short' formatting option. Figured I can add a custom one later.
Do I need to format the times in the controller for the controller with the nested attributes? Or can I format them in the model that handles storing the times? Let me know if you need more information or code.
I'm not sure if these are the best options, but here are the two I found:
1) Pass an instance variable to the partial with the fields value. Instance variables allowed me to format the datetime field using to_s(:custom_format).
2) I'm using Simple Form, and found that using their time format worked well. For example:
<%= f.input :close, as: :time, ampm: true, minute_step: 15 %>
You can pass through any of the default datetime_select parameters to Simple Form.
The second option adds the meridian option (AM/PM) to the hour field, which was a little strange to me. But it seemed to be the simplest solution of the two, so I went with that for now.

Using a page variable as an if statements conditon within a control

I have the following problem:
I have the variable $GiftID on my page.
I want to cycle through all of my gift objects using my function getGifts().
When the $ID of the gift is equal to the $GiftID of the page then I want something to happen.
Here is an example of my code:
$GiftID
<% control getGifts %>
<% if CurrentPage.GiftID = ID %>This is it!<% end_if %>
<% end_control %>
Using $CurrentPage.GiftID works when printing inside the control, but how on earth do I access it from within the if statement?
I am using SS 2.9
I have not used ss2.9 yet, but as far as I know you can not do <% if Top.GiftID = ID %> in any 2.x version, you can not compare 2 variables, you can only compare with static vaules. (but it is possible in 3.0)
So you have to do it on php side, if you want to only display the slected gift object, then:
if GiftID is actually the DB field for the has_one relation of Gift then you can just do <% control Gift %> and it will scope the Gift object with the GiftID
If you really have GiftID saved as DB field or otherwise, then can do
public function getGift() { return DataObject::get_by_id('Gift', $this->GiftID); }
both ways you can do <% control Gift %> and it will scope it
If you want to list all gifts and mark the current gift then you need to do it on php side (foreach the set of objects and set a flag on the current object)
You should be able to access the current page with Top:
<% control getGifts %>
<% if Top.GiftID = ID %>This is it!<% end_if %>
<% end_control %>

How to make If statements in Databound ListView

I have a ListView with many advanced controls and html tags. ListView is bound to collection of profiles when first profile in collection is current profile. current profile has few differences from other profiles ie. flash embed, js and some other stuff. I can access inside of my ListView Container.DataIndex property which gives me 0 as first item in index but i'm unable to use inline If statements like so
<% If Container.DataIndex = 0 Then %>
do stuff
<% EndIf %>
this is because i must place pound to access databound item but neither this
<%# If Container.DataIndex = 0 Then %>
do stuff
<% EndIf %>
How can i make inline If ?
Try this:
<% if (DataBinder.Eval(Container, "DataItemIndex")) { %>
do stuff
<% } else { %>
do other stuff
<%} %>
Here is a small summary of the inline aspx tags:
http://naspinski.net/post/inline-aspnet-tags-sorting-them-all-out-%283c25242c-3c253d2c-3c252c-3c252c-etc%29.aspx
But i would recommend to use ListView.ItemDataBound. It is less error-prone and more readable in codebehind.
Did you mean IIF? IIF - Returns one of two objects, depending on the evaluation of an expression.

Resources