tags:

views:

895

answers:

2

I'm just starting out in Grails and need some advice on using Ajax. I want to append some html to the bottom of a div inside a form. This is basically what I have:

-form-
  -div id="listOfchildren"-
   childrow 1 input fields 
   childrow 2 input fields 
   childrow 3 input fields
  -/div-
-form-
-a-Add Child 4-/a-

When I click on the "Add Child" I want to make an ajax call that results in a new childrow getting inserted into the "listOfchildren" div. So the document would look like this:

-form-
  -div id="listOfchildren"-
   childrow 1 input fields
   childrow 2 input fields
   childrow 3 input fields
   childrow 4 input fields
  -/div-
-form-
-a-Add Child 5-/a-

In Rails I would do something simple like this:

  render :update do |page|
     page.insert_html :bottom, "list_of_children", :partial => child_partial
     page.replace "add_link", :partial => 'add_link'
   end

The previous code sends an javascript back to the browser with two commands. The first command tells the browser to append some html to the bottom of a div. The second command updates the "add link" counter.

In grails I can only see how to replace an entire div (which would wipe out the user's existing input) and I don't see how I can call multiple functions from the ajax response. I can probably do this if I was to write some javascript functions in prototype or whatever, but I'd like to avoid that if there is a simpler way.

Thanks!

Nate

A: 

First, you need to add prototype.js to your header of the page, or if applicable to the header in your layout template:

<g:javascript library="prototype" />

Then instead of the a link use the remoteLink tag that comes with Grails:

<g:remoteLink action="ajaxyAddChild" update="listOfChildren">
    Add Child 4
</g:remoteLink>

The remoteLink tag will default to go back to the controller that called the render for the page. So you just need to add a method called ajaxyAddChild, or whatever you want to call it, and have it do the business logic (better put into a Service) and output the HTML you want to render in that div - or render a GSP file for that div. The update= part of the remoteLink is the id of the element on the page to update.

MattS
Hi Matt,Thanks for the answer. That would normally work, but I didn't explain that I am working with form fields inside the div. I want to append the output from ajaxyAddChild to the bottom of the div and not replace the entire div. I don't want to erase the user's input each time they add a new child.Thanks again for the help. If you've got any ideas on the append part it would be great!
I re-read this and I'm wondering why you're calling the server if you're not doing any business logic on the data from the form - just appending another row of input fields and changing a button. You should be able to do all of that just in the browser with Javascript. Just get the contents of the div to some variable, append new stuff and output back to the div. If you are running some business logic, but didn't post that part, couldn't you submit the form and have the gsp return the new form to the div with the appended fields, preserving data?
MattS
A: 

There is a plugin for grails which allows you to do rails-esque render :update calls. This plugin will let you do exactly what your rails code did above. The plugin is called "dynamic javascript" and can be found at http://grails.org/Dynamic+Javascript+Plugin. It looks like the plugin doesn't have an out-of-the-box insert_html method, so using this plugin your render :update block would become (I haven't tested this so tell me if it doesn't work):

renderJavascript{
  callFunction "$('list_of_children').insert", g.render(template: 'child_template')
  replace 'add_link', [text:g.render(template:"add_link")]
}

However, I agree with mattS that it seems odd to make a call to the server to do this. Couldn't this be done client-side with javascript?

David Chanin