Feedback on my dynamic forms solution

Hey all :wave:t2:

I’m working on an App where the user can add multiple items to a record, a simple has_many and belongs_to. The user has to add at least one item and can add multiple items by clicking a button and a new input field appears with a button to remove it. I struggled a lot with it especially because I don’t know much about Javascript (been a backend since I can remember) but I made it work (and I’m not happy with the solution).

Some context: this is a Raffle app where the user can describe many Prizes being the prize a simple description of the product/service.

This is the form where the user creates the raffle and add a prize:

<%= content_tag :div, class: 'control' do %>
  <label class="label">Prizes</label>
  <%= link_to 'Add prize', add_prize_raffles_path, class: 'button is-info mb-3', data: { turbo_method: :post } %>
  <ul id="prize_list" data-raffle-target="prizeList">
    <div class="field has-addons">
      <p class="control is-expanded">
        <%= text_field_tag(:prize_0_description, '', class: 'input mb-2', required: true, name: "prizes[0][description]") %>
      </p>
    </div>
  </ul>
<% end %>

upon clicking Add prize, a turbo stream action is executed that does this:

add_prize.turbo_stream.erb

<%= turbo_stream.append "prize_list" do %>
  <% random_prize_id = rand(900_000) %>
  <%= tag.div class: 'field has-addons', id: "prize_#{random_prize_id}" do %>
    <p class="control is-expanded">
      <%= text_field_tag("prize_#{random_prize_id}_description", '', class: 'input mb-2', required: true, name: "prizes[#{random_prize_id}][description]") %>
    </p>
    <p class="control">
      <%= link_to 'Remover', '#', class: 'button is-danger', data: { action: 'click->raffle#removePrize:prevent:stop', raffle_id_param: random_prize_id } %>
    </p>
  <% end %>
<% end %>

See, this is where I’m not happy: because I can’t repeat the prize id in the HTML (e.g. prize_0_description again) and I didn’t find a nice way to compute the next prize id sequentially, I simply get a random number from a reaaaaly high number hahaha…I mean, if it is stupid and it works, then it’s not stupid, right? anyway, it does the trick but I hate this code…

I tried to do it all via Stimulus but I don’t know how to create this rather “complex” HTML on the controller and append it to the list

appreciate any ideas

Your solution is the correct solution.

Never try to do that. Stimulus is fine for changing the innerHTML of an element. But, creating a whole element(a new price element) is hard and counter productive.

Your approach is nice and elegant. The only thing you can improve upon is the random id generation. By using an id generator like Nanoid

1 Like

Yeah, I’m inclined to agree with you. Trying to do that with Stimulus is hard…I will follow this path. Thanks a lot!

1 Like