Earlier this week a user asked me to look into something odd with CF901's new multirowselect feature for cfgrid. If you haven't played with this yet, it is a way to enable multiple row selections in a grid. Unfortunately it doesn't quite work as advertised, but in this blog entry I'll tell you how to make it work.
First, let's start with a simple example so you can see what the attribute does when enabled.
<cfform name="mytest" method="post">
<cfgrid name="SelectStuff" query="q" format="html" width="400" height="250" multirowselect="true"></cfgrid>
<cfinput type="submit" name="submit" value="Submit">
</cfform> <cfdump var="#form#">
<cfset q = queryNew("id,name")>
<cfloop index="x" from="1" to="10">
<cfset queryAddRow(q)>
<cfset querySetCell(q, "id", x)>
<cfset querySetCell(q, "name", "Name #x#")>
</cfloop>
My code begins with a quick fake query on top. Next I've got a cfform with my grid inside. The only thing really interesting there is the multirowselect. I also added a quick dump of the form scope to the bottom. Let's take a look at how the grid is changed. I'll first show a picture with the option turned off, this is the default:
Now let's turn the option back on, as in the code above.
As you can see, there is a new column now with checkboxes. There is also a checkbox on top. Clicking that works as a Select All/Deselect All feature. So in theory, that should be it, right? Unfortunately, it completely doesn't work as shown above. If I click a few checkboxes and hit submit, I get this in the form scope.
Nothing. Ugh. So I pinged Adobe on this. Turns out - the real expectation for this feature was within Ajax-based applications. You can get the value just fine via JavaScript, but if you don't do this, nothing will be sent to the server. I've already filed a bug report on this.
So how can you make this work? The simplest solution is to use the getSelectedRows API:
obj = ColdFusion.Grid.getSelectedRows('SelectStuff');
This returns a struct of objects. How do you send that to the server? One option would be to turn into JSON:
jsonbj = ColdFusion.JSON.encode(obj);
However, this will give you a JSON representation of the entire row. You probably only want the ID values, right? Here is the code I came up:
var selected = "";
for(var i=0; i<obj.length; i++) {
if(selected == "") selected = obj[i].ID;
else selected += "," + obj[i].ID;
}
document.getElementById('selected').value = selected;
Basically - create a list of IDs from the object and assign it to a new form field, in this case, a hidden one. You can try this yourself via the demo link below, and I've pasted the entire completed template below.
<cfset q = queryNew("id,name")>
<cfloop index="x" from="1" to="10">
<cfset queryAddRow(q)>
<cfset querySetCell(q, "id", x)>
<cfset querySetCell(q, "name", "Name #x#")>
</cfloop> <script>
function fixMe() {
obj = ColdFusion.Grid.getSelectedRows('SelectStuff');
var selected = "";
for(var i=0; i<obj.length; i++) {
if(selected == "") selected = obj[i].ID;
else selected += "," + obj[i].ID;
}
document.getElementById('selected').value = selected;
return true;
}
</script> <cfform name="mytest" method="post" onSubmit="return fixMe()">
<cfgrid name="SelectStuff" query="q" format="html" width="400" height="250" multirowselect="true"></cfgrid>
<input type="hidden" name="selected" id="selected">
<cfinput type="submit" name="submit" value="Submit">
</cfform> <cfdump var="#form#">