Wednesday, July 15, 2009

Grails - ajax driven select and saving the selection

A couple of days ago I discovered the need of ajax populated forms to improve the navigation of the current website I'm working on.

And some nice person wrote a great tutorial about this here, but there was one thing missing. I wanted to render some elements on the same page and keep the selection stored in the text field.

The default approach is the following grails tag:


<g:select id="machine" name="machine" value = "${machine}"/>


but since this field is populated by an ajax function, the value can never be set,since the population happens after the page is loaed, so what can we do?

We enhance our little bit of java script and define the selection in there


//update the machine tag with the received values
function updateMachine(e) {
// The response comes back as a bunch-o-JSON
var machines = eval("(" + e.responseText + ")"); // evaluate JSON


if (machines) {
var rselect = document.getElementById('machine');

// Clear all previous options
var l = rselect.length;

while (l > 0) {
l--;
rselect.remove(l) ;
}

// Rebuild the select
for (var i = 0; i < machine =" machines[i];" opt =" document.createElement('option');" text =" machine;" machine = <%=machine%>'){
opt.selected = machine;
}
//just add another field and work with the default selection
else{
opt.value = machine;
}
try {
rselect.add(opt, null); // standards compliant; doesn't work in IE
}
catch(ex) {
rselect.add(opt); // IE only
}
}
}
}

//initilaize the variables on page load
var zselect = document.getElementById('database') ;
var zopt = zselect.options[zselect.selectedIndex]
${remoteFunction(controller: 'query', action: 'listmachines_ajax', params: '\'database=\' + zopt.value', onComplete: 'updateMachine(e)')}



we basically assume that our controller inject a variable with the name 'machine' on submitting the form. A controller closure could look like this:


def showTimeLine_ajax = {

assert params.database != null, "you need to provide the database in the params object"
assert params.machine != null, "you need to provide the machine in the params object"

def model = new HashMap()

//build our model, implementation not shown because of copyright
//model = buildModel(params.database,params.machine)

model.database = params.database
model.machine = params.machine

return model
}



and our form is simple enough


<g:form name="select_database_machine_form" method="post">
<g:select id="database" name="database" from="${dbs}" value="${database}"

onchange="${remoteFunction(
controller:'query',
action:'listmachines_ajax',
params:'\'database=\' + escape(this.value)',
onComplete:'updateMachine(e)')}"/>
<g:select id="machine" name="machine"/>

<g:submitToRemote action="showTimeLine_ajax" update="graph_content" value="execute query"/>
</g:form>

No comments:

Post a Comment