Topic: Dynamically creating form fields

I'm writing an application which stores people. People can have a number of addresses.

I'd like to have a form whereby clicking on a button ('Add address' say) would create some extra fields for a new address to be added.

Ideally the address would be submitted using AJAX then added to a list of existing addresses on the form. This list would have 'Edit' and 'Delete' buttons next to the entries so they be altered. Deleting would also be handled by and AJAX request.

Does anyone know any good examples for this sort of behaviour? Can anyone offer some pointers as to how this can be achieved?

Re: Dynamically creating form fields

I have done this a couple times in the past. I recommend creating an Addresses controller. You can then use link_to_remote to call new, edit, and destroy on the addresses controller. The action can return the proper response/partial and update the proper divs.

I may write a tutorial on this and go into more detail.

Railscasts - Free Ruby on Rails Screencasts

Re: Dynamically creating form fields

ryanb wrote:

I have done this a couple times in the past. I recommend creating an Addresses controller. You can then use link_to_remote to call new, edit, and destroy on the addresses controller. The action can return the proper response/partial and update the proper divs.

I may write a tutorial on this and go into more detail.

I have an Addresses controller so I can call these methods. It's the first time I've done anything like this so I'm trying to sort out how it will work in my head.

A few questions:

- What should create the new fields? Pure JavaScript (i.e. this sort of technique http://developer.mozilla.org/en/docs/DO … nsertRow)? Or Rails Helpers?

- If I wrote some JavaScript that created the new form fields would I be able to use this? Or is there a better way? Prototype maybe?

- If this addresses section of the form is submitted separately to the rest of the form will the 'Save' button fire off some JavaScript as opposed to submitting the form?

- Will the new, edit, and destroy actions be the same as those in a non-AJAX environment accept that they will return some HTML for between the relevant divs?

- Do you know of any example code anywhere on the web? Something simple to get me started would be great.

Re: Dynamically creating form fields

mip wrote:

- What should create the new fields? Pure JavaScript (i.e. this sort of technique http://developer.mozilla.org/en/docs/DO … nsertRow)? Or Rails Helpers?

I would use Rails helpers.

mip wrote:

- If I wrote some JavaScript that created the new form fields would I be able to use this? Or is there a better way? Prototype maybe?

You can do this completely without writing a line of JavaScript using rails helpers and prototype (link_to_remote for example). You may need to use RJS as well.

mip wrote:

- If this addresses section of the form is submitted separately to the rest of the form will the 'Save' button fire off some JavaScript as opposed to submitting the form?

If you use form_remote_tag it will send the form through JavaScript.

mip wrote:

- Will the new, edit, and destroy actions be the same as those in a non-AJAX environment accept that they will return some HTML for between the relevant divs?

They will be a little different depending upon how you do it. For example, you may want to only render a partial in the new and edit actions. You will also want to reload the addresses div inside the create/update/destroy actions instead of redirecting.

mip wrote:

- Do you know of any example code anywhere on the web? Something simple to get me started would be great.

Not off the top of my head. I would look for AJAX/RJS Rails specific tutorials. Most of the tutorials do something similar to what you are attempting to do from what I've seen.

Railscasts - Free Ruby on Rails Screencasts

Re: Dynamically creating form fields

Cheers Ryan. Much appreciated.

ryanb wrote:
mip wrote:

- If I wrote some JavaScript that created the new form fields would I be able to use this? Or is there a better way? Prototype maybe?

You can do this completely without writing a line of JavaScript using rails helpers and prototype (link_to_remote for example). You may need to use RJS as well.

Hmmm.

Re: Dynamically creating form fields

So I need to do the following:

1. Create an action on my address controller which returns a HTML form for adding an address (using a partial).

2. Use link_to_remote to call this action and dynamically draw the form.

3. Create an action on the address controller which is called when the form segment is submitted. the action should create the address and link it to the person.

4. Create actions on the address controller which provide the delete and edit functionality.

Last edited by mip (2006-11-15 11:39:58)

Re: Dynamically creating form fields

Ryan. Isn't this a similar problem to your tutorial here http://railsforum.com/viewtopic.php?id=1065 ?

Re: Dynamically creating form fields

The significant difference is the tutorial shows you how to do everything in one form. Your solution will be simpler because you don't need to do it in one form. You can just list the addresses and use link_to_remote for removing, editing, and adding addresses.

Also, the tutorial only shows creating, not editing/removing existing models.

Railscasts - Free Ruby on Rails Screencasts

Re: Dynamically creating form fields

ryanb wrote:

The significant difference is the tutorial shows you how to do everything in one form. Your solution will be simpler because you don't need to do it in one form. You can just list the addresses and use link_to_remote for removing, editing, and adding addresses.

I understand how I use link_to_remote to get the extra part of the form (I have this working) but how do I use it to submit the extra fields independently of the main form?

I have an "Add address" link which uses link_to_remote to put the following between some div tags:

<label for="address_address">Address</label>
<%= text_field 'address', 'address'%>
<label for="address_postcode">Postcode</label>
<%= text_field 'address', 'postcode'%>

But how do I submit this independently of the rest of the form? I can't use form_remote_tag as it submits the whole of the form.

I could use link_to_remote but how do I get what's been entered into the fields?

Last edited by mip (2006-11-15 11:50:46)

Re: Dynamically creating form fields

Sorry, I think I misunderstood your original problem. I assumed you were adding addresses on the Person's Show page (where there isn't already a form). But, if you want to add addresses while editing/creating a person (where there is already a form) then yes, the article I wrote will be what you want. Right now it only handles creation, but I plan to write one up which can create/edit addresses while editing the person as well.

How it handles the form submission problem is it submits all data (address and person fields) at once in one big form then sorts it all out in the resulting action, so there's no need to submit data independently.

Railscasts - Free Ruby on Rails Screencasts

11

Re: Dynamically creating form fields

ryanb wrote:

Sorry, I think I misunderstood your original problem. I assumed you were adding addresses on the Person's Show page (where there isn't already a form). But, if you want to add addresses while editing/creating a person (where there is already a form) then yes, the article I wrote will be what you want. Right now it only handles creation, but I plan to write one up which can create/edit addresses while editing the person as well.

Thank ryan. Yep that's what I want.

ryanb wrote:

How it handles the form submission problem is it submits all data (address and person fields) at once in one big form then sorts it all out in the resulting action, so there's no need to submit data independently.

The problem is that I really need to do this submission independently. Once a new address is created I add it to a list so the user can select the persons preferred address. I have that bit working it's creating the new address which is causing me the problems.

For example, the following doesnt work. It submits the whole page:

<%= form_remote_tag :url => {:action => 'add_address'}, :update => 'address-table' %>
<label for="address_address">Address</label>
<%= text_field 'address', 'address', "size" => 60 %>
<label for="address_postcode">Postcode</label>
<%= text_field 'address', 'postcode', "size" => 20 %>
<%= submit_tag 'Save address'%>
<%= end_form_tag%>

(in fact when this partial is rendered the forms tags aren't even created)

I really want something which will just pass the values of these fields to my action so I can create the address.

I'm guessing there a different helper to form_remote_tag which I need to use but I don't know which.

If I use submit_to_remote or remote_function how do I pass the contents of the fields to the action?

Last edited by mip (2006-11-15 15:19:19)

Re: Dynamically creating form fields

Are you including this form_remote_tag in an already existing form? HTML doesn't allow nested forms. Instead I suggest placing it outside (below/above) the person form. Then it should submit properly with only those fields.

Railscasts - Free Ruby on Rails Screencasts

13

Re: Dynamically creating form fields

I think I can do this using submit_to_remote.

I have:

<label for="address_address">Address</label>
<%= text_field 'address', 'address', "size" => 60 %>

<label for="address_postcode">Postcode</label>
<%= text_field 'address', 'postcode', "size" => 20 %>

<%= submit_to_remote 'save', 'Save address', :url => {:action => 'add_address', :id => person.id}, :update => 'address-table' %>


but what do I need in the add_address action?

I thought I could have:

  def add_address
    @person= Person.find(params[:id])
    @address = @person.build_address(params[:address])
    if @person.save
      @address.save
    end   
    render :partial => 'address_list', :locals => {:person => @person}
  end

but I get:

undefined method `build_address' for #<Person:0x36ef278>

Last edited by mip (2006-11-15 15:32:03)

14

Re: Dynamically creating form fields

ryanb wrote:

Are you including this form_remote_tag in an already existing form? HTML doesn't allow nested forms. Instead I suggest placing it outside (below/above) the person form. Then it should submit properly with only those fields.

I can't do that. It'll ruin the layout of my page. Or can I?

Last edited by mip (2006-11-15 15:37:38)

Re: Dynamically creating form fields

You could write some custom javascript to fetch the values in the fields and pass them with the AJAX request then. This is a little beyond me unfortunately.

Railscasts - Free Ruby on Rails Screencasts

16

Re: Dynamically creating form fields

ryanb wrote:

You could write some custom javascript to fetch the values in the fields and pass them with the AJAX request then. This is a little beyond me unfortunately.

The submit_to_remote does this for me. See this post http://railsforum.com/viewtopic.php?pid=6090#p6090. I'm just not sure what I need in the action.

Last edited by mip (2006-11-15 15:41:56)

17

Re: Dynamically creating form fields

mip wrote:

I thought I could have:

  def add_address
    @person= Person.find(params[:id])
    @address = @person.build_address(params[:address])
    if @person.save
      @address.save
    end   
    render :partial => 'address_list', :locals => {:person => @person}
  end

but I get:

undefined method `build_address' for #<Person:0x36ef278>

Or do I do:

@person = Person.find(params[:id])
@address = Address.new(params[:address])

and then something to add the address to the person? Whatever that is.. smile

Last edited by mip (2006-11-15 15:56:20)

Re: Dynamically creating form fields

submit_to_remote will submit all the fields, but I guess that's fine. smile

As for what goes in the action you need to create the address based on the fields:

@address = Address.create(params[:address])

Then place the addresses in a partial and render that. This will replace the content of the div with the partial.

render :partial => 'addresses', :layout => false

Edit: Oh, looks like you're pretty much doing this already. You can set the person_id as a hidden field in the address form. Or you can build it as you are doing in your previous post. Either way should work.

Last edited by ryanb (2006-11-15 15:57:11)

Railscasts - Free Ruby on Rails Screencasts

Re: Dynamically creating form fields

mip wrote:

but I get:

undefined method `build_address' for #<Person:0x36ef278>

Try:

@person.addresses.build(params[:address])

Railscasts - Free Ruby on Rails Screencasts

20

Re: Dynamically creating form fields

ryanb wrote:
mip wrote:

but I get:

undefined method `build_address' for #<Person:0x36ef278>

Try:

@person.addresses.build(params[:address])

Hmmm.

undefined method `build' for Address:Class