user82302124 user82302124 - 1 year ago 148
Ajax Question

Grails - Updating a table with data that already exists during an AJAX call

I have a little dilemma and believe this could be a design issue. I have a list of contacts returned to my view (searchResults) based on some criteria (check boxes, etc). Essentially an advanced search.

Each contact has three links in a field set that either allows editing, showing details, or 'hitThis'. The hitThis method performs a series of tasks that will generate three new values for a contact - age, size, speed. When I click that link, I want to basically update that row only with the new values (columns already exist, just empty).

I have a div in my gsp that contains a table that displays the searchResults list. During my form submit for the search results, I return a list of contacts that updates my template where the div exists. This works fine.

In that div, I have a form as such:

<td>
<g:form>
<fieldset class="buttons">
<g:hiddenField name="id" value="${contactInstance?.id}" />
<g:set var="searchResults" value="${searchResults}" /><br/>
<g:set var="cID" value="${contactInstance?.id}" /><br/>
<g:actionSubmit class="edit" action="edit" value="${message(code: 'Edit')}"/>
<g:actionSubmit class="show" action="show" value="${message(code: 'Show')}"/>
<g:remoteLink action="hitThis" value="Click Me" update="searchResultsDiv" params="[searchResults:searchResults, cID:cID]"/>
</fieldset>
</g:form>
</td>


When I select the remote link for hitThis, I want to perform an action that will update three columns that are attached to that contactInstance row in the searchResults template:

Before click:


myName age size speed
Tom empty empty empty


After click:


myName age size speed
Tom 20 6 4.9


I thought the rendering would handle it, but the call to hitThis won't return the searchResults list (which could be quite large) that was initially passed to update that table. I would prefer not passing BACK the list, since I feel this is excessive and performance crippling.

I could just redirect the user to that contact's information page (show), but I would rather update the table on the fly.

How can I simply update a div or even a table row, after my hitThis call and without having to pass everything back to the controller to only have to pass it back again?




Edit:

So my results now according to the example you gave me is similar to this (name is Ted, size is 5, speed is 4:

name size speed
Ted54 Ted54 Ted54


Here is part of my view:

<td id="name-${contactInstance.id}"><g:render template="name" model="['contactInstance':contactInstance]"/></td>
<td id="size-${contactInstance.id}"><g:render template="size" model="['contactInstance':contactInstance]"/></td>
<td id="speed-${contactInstance.id}"><g:render template="speed" model="['contactInstance':contactInstance]"/></td>

<fieldset class="buttons">

<g:hiddenField name="id" value="${contactInstance?.id}" />
<g:remoteLink action="moreInfo" params="['cid':contactInstance?.id]" onSuccess="updateData(data,'${contactInstance?.id}'), updateData2(data,'${contactInstance?.id}'), updateData3(data,'${contactInstance?.id}')" >TEST</g:remoteLink>
</fieldset>


Here is my Javascript:

<script>
function updateData(data, id) {
alert(data);
$('#name-'+id).html(data);
}

function updateData2(data, id) {
alert(data);
$('#size-'+id).html(data);
}

function updateData3(data, id) {
alert(data);
$('#speed-'+id).html(data);
}
</script>


And my controller method:

def moreInfo() {
def contactInstance = Contact.get(params.cid)

contactInstance.name= "Ted"
contactInstance.size= "5"
contactInstance.speed= "4"

if (contactInstance.save(flush: true)) {
println(contactInstance)
}

render(template:'name', model:[contactInstance:contactInstance])
render(template:'size', model:[contactInstance:contactInstance])
render(template:'speed', model:[contactInstance:contactInstance])
}

Answer Source

You can manipulate your DOM using javascript after the remote call returns.

(I'm not sure why you need to pass the entire searchResults with the remote call. It could be a rather large structure. You may consider storing it in the session instead and manipulate it over there. Of course, this is a design decision for you to take.)

Another way to think about this is to create a template for the form. Then render that template with the remote call (replacing the existing one within the td).

template: _myform.gsp

  <g:form>
    <fieldset class="buttons">
      <g:hiddenField name="id" value="${contactInstance?.id}" />
      <g:set var="searchResults" value="${searchResults}" /><br/>
      <g:set var="cID" value="${contactInstance?.id}" /><br/>
      <g:actionSubmit class="edit" action="edit" value="${message(code: 'Edit')}"/>
      <g:actionSubmit class="show" action="show" value="${message(code: 'Show')}"/>
      <g:remoteLink action="hitThis" value="Click Me" update="searchResultsDiv" params="[searchResults:searchResults, cID:cID]"/>
    </fieldset>
  </g:form>

then your normal page gsp can be:

...
<tr>
  <td>
    <g:render template="myform" />
  </td>

  <td>
    <g:render template="myform" />
  </td>
</tr>
...

and in the 'hitThis' action,

def hitThis() {
    ...
    render(view: "myform")
}

finally, use javascript to replace the form in the 'td' at the client end

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download