# Dynamic form elements via AJAX

**URL:** <https://www.ruby-forum.com/t/dynamic-form-elements-via-ajax/75300>\
**Category:** Rails\
**Created:** [November 8, 2006, 11:40pm UTC](https://www.ruby-forum.com/t/dynamic-form-elements-via-ajax/75300 "2006-11-08T23:40:56Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![misleb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/e5b9ba/32.png) [@misleb](https://www.ruby-forum.com/u/misleb)\
**Post date:** [November 8, 2006, 11:40pm UTC](https://www.ruby-forum.com/t/dynamic-form-elements-via-ajax/75300/1 "2006-11-08T23:40:56Z")

</div>

I’m trying to build a form with an ordered list of elements. You can  
add/remove an arbitrary number of items. I can use link\_to\_remote to  
insert a new element, but I am having problems maintaining order when it  
comes to submitting the form. Here is my “element”:

- "\> \<%= text\_field\_tag "choice\_#{i}[text]", choice[0], :size =\> 16, :id =\> "choice\_#{i}\_text" %\> \<%= text\_field\_tag "choice\_#{i}[value]", choice[1], :size =\> 4, :id =\> "choice\_#{i}\_value" %\> \<%= link\_to\_remote '+', :url =\> {:action =\> 'insert\_choice', :id =\> "choice\_#{i}" } %\> \<%= link\_to\_function '-', "Element.remove('choice\_#{i}')" %\>

It is actually a set of two text\_fields, as you can see. When the form  
is initially built with a default of 3 “choices,” the order is given by  
choice\_0, choice\_1, etc. But when insert a new “choice”

- via ajax it  
doesn’t have a proper name/id. I can call it “choice\_new” or something  
but when the form is submitted the controller won’t know what order they  
were in the form.

Any suggestions?

-matthew

---

<div class="post-metadata">

**Author:** ![misleb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/e5b9ba/32.png) [@misleb](https://www.ruby-forum.com/u/misleb)\
**Post date:** [November 9, 2006, 12:04am UTC](https://www.ruby-forum.com/t/dynamic-form-elements-via-ajax/75300/2 "2006-11-09T00:04:52Z")

</div>

Hmmmmmmmmm. You could create a hash and populate it with a mapping of  
position to choice\_id. You will need to generate a unique ID for each  
added choice… I would try storing the mapping and the ‘current ID’ in  
the session. Then, when you create a new choice:

- Add one to the current ID in the session and use it for the choice  
ID. Save it to the session.
- Get the hash from the session. Add the ID to it, pointing to the  
position. You will have to add one to all hash values greater than the  
position you want to insert to first.
- Save the hash to the session.

Deleting would be the same in reverse…

Does that make sense?

Ben

---

<div class="post-metadata">

**Author:** ![misleb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/e5b9ba/32.png) [@misleb](https://www.ruby-forum.com/u/misleb)\
**Post date:** [November 9, 2006, 12:29am UTC](https://www.ruby-forum.com/t/dynamic-form-elements-via-ajax/75300/3 "2006-11-09T00:29:56Z")

</div>

Hmm, I never thought of storing the the choices in the session. So you  
would suggest redrawing the entire list each time a choice is added or  
deleted as opposed to trying to play it cheap and just insert/remote  
individual items?

-matthew

---

<div class="post-metadata">

**Author:** ![misleb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/e5b9ba/32.png) [@misleb](https://www.ruby-forum.com/u/misleb)\
**Post date:** [November 9, 2006, 5:03am UTC](https://www.ruby-forum.com/t/dynamic-form-elements-via-ajax/75300/4 "2006-11-09T05:03:31Z")

</div>

Matthew I. wrote:

> \<%= link\_to\_remote ‘+’, :url =\> {:action =\> ‘insert\_choice’, :id =\>  
> “choice\_#{i}” } %\>  
> \<%= link\_to\_function ‘-’, “Element.remove(‘choice\_#{i}’)” %\>
> 
> It is actually a set of two text\_fields, as you can see. When the form  
> is initially built with a default of 3 “choices,” the order is given by  
> choice\_0, choice\_1, etc. But when insert a new “choice”
> 
> - via ajax it  
> doesn’t have a proper name/id. I can call it “choice\_new” or something  
> but when the form is submitted the controller won’t know what order they  
> were in the form.

I’d recommend changing to

\<% @choices = Array.new(3, Choice.new) if @choices.empty %\>

\<% @choices.each do |choice| %\>- \<%= text\_field\_tag 'choice\_text[]', choice.text, :size =\> 16 %\> \<%= text\_field\_tag 'choice\_value[]', choice.value, :size =\> 4 %\> \<%= link\_to\_function '+', 'var c=this.parentNode;c.parentNode.insertBefore(c.cloneNode(true),c)' %\> \<%= link\_to\_function '-', 'var c=this.parentNode;c.parentNode.removeChild(c)' %\>
\<% end %\>

Now there’s no numbering or ids to maintain, the texts and values  
are each posted as arrays, respecting their order in the document,  
the client-side insertion and deletion of choices is much more  
responsive for the user, and you no longer need to include Prototype.

However for efficiency in actual implementation the scripts  
should be made page-wide functions that are called from each link.

–  
We develop, watch us RoR, in numbers too big to ignore.

---

<div class="post-metadata">

**Author:** ![misleb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/e5b9ba/32.png) [@misleb](https://www.ruby-forum.com/u/misleb)\
**Post date:** [November 9, 2006, 7:14pm UTC](https://www.ruby-forum.com/t/dynamic-form-elements-via-ajax/75300/5 "2006-11-09T19:14:51Z")

</div>

Excellent. I wasn’t aware that I could use name[] as a field name.  
Solves all my problems. Well, now I am not sure that I really want to  
“clone” the node. I may have to put some extra JS in there to clear the  
text\_field values on the new node.

-matthew
