Here is a question forwarded to me from Ben Forta. He thought I could take a stab at it so here is my answer.
This is something I kind of touched on before. When you pass a query to a cfgrid, you can include HTML in the query data. This HTML will render in the grid. So consider the following code.I am putting a query result set into a
from a cfc bind statement (which works with no problem). What I want to be able to do is have one grid column with an "ADD" button in it. When the button/cell is clicked it invokes another function that writes some data to a database. Everything I have read only addresses the edit/delete mode of the grid data itself. I want to "click" the item and have it add to another list/container/database.
<cfquery name="entries" datasource="cfartgallery" maxrows="12">
select *
from art
</cfquery>
<cfset queryAddColumn(entries, "add", arrayNew(1))>
<cfloop query="entries">
<cfset querySetCell(entries, "add", "<input value='Add' type='button' onclick='javascript:testit(#artid#)'>", currentrow)>
</cfloop>
I took a simple query and added a new column, "add". I looped over the query and for each row, added an HTML button that calls a JavaScript function and passes the primary key of the row.
Just to ensure it works, here is the rest of the code:
<script>
function testit(x) { alert(x);}
</script>
<cfform name="test">
<cfgrid autowidth="true" name="entries" format="html" query="entries" width="600">
<cfgridcolumn name="artid" display="false">
<cfgridcolumn name="artname" header="Name">
<cfgridcolumn name="price" header="Price">
<cfgridcolumn name="add" header="Add">
</cfgrid>
</cfform>
If you run this in your browser, you can click on any button and see the JavaScript called. So that's the difficult part really. If you want to pass this 'add action' to the server, you can use cfajaxproxy. I assume this part is easy, if folks want to see that part of the code, I can work that up as well.
Archived Comments
Hi Ray,
Thanks for the post -- I've been meaning to look into this for a while and havent had the time. If you have a sec, I'd like to see the "add action" code via an AjaxProxy that you mentioned. I've yet to see a good "real world" example of cfajaxproxy out there anywhere in blogland.
Thanks!
If you're doing this on every row, wouldn't it be more of an 'Edit' button then an 'Add'? Yeah, I know...semantics ;)
Another cool option that Stroz thought of is to add a double click listener to each row and open a cfwindow on double click...
I don't think his intent was to be an Edit, but more a 'Here is a list of data. Select the ones you want on your page', so Add would make sense. You would then want to change the button on the fly to a remove.
Ray -
I don't believe you want "javascript:" on the onclick event.
Pat
Ray: I get ya now...
Patrick: Why doesn't he want that?
Nice. Anyone know how to turn paging off for cfgrid? Yeah, yeah, I know thats one of the main points of cfgrid but my client wants to see it all on one page.
@Pat - you are right - although it seemed to work.
@Sam - use the pagesize attribute. You would need to do a CF query before hand though to get the count, but that is a very small query.
Ray -
The only time you need it is with the "Href" part of the anchor tag <a href="javascript:x(); " >aaa</a>
Actually, the onclick for that tag is better..that "href="javascript:" is part of IE 5 and Netscape 4+.
Somewhat off topic, but do you get hyphen hyperlinks in your cfgrid rows that are empty? If the grid accepts 10 rows, but the resultset only has 8 rows...the last two rows will be filled with hyperlinked hyphens with a cfgridkey=null. Do you know how to get rid of them? Any assistance is greatly appreciated. Thanks.
Hey, I was the one that originally asked about this capability and Ray I appreciate you addressing it so quickly. I am going to take your suggestion and see if I can apply it into my logic. I will update you on the attempt.
For those that was asking why...The intended use of something like this is to allow someone to pick an item from a cfgrid result list and by selecting the "ADD" button from a cfgridcolumn it would insert that item into their "basket" which in this case is an associated database table insert. The basket display box would have a bind statement that would asynchronously pull what was current in their basket. I felt that the cfgrid was a better/easier display method opposed to just a standard <table> layout. Right or wrong...I was attempting to let the cfgrid be my "table layout".
Oh...and the <cfajaxproxy> concept would also be helpful.
This is working great!!! I wanted to post an example of my code up to this point, and following along with the "art theme" that Ray used.
/*** ART_LIST.CFM file contents ***/
<script>
function testit(x) { alert(x);}
</script>
<cfform name="form" action="act_art.cfm" method="post" format="html">
<table>
<tr>
<th>Module Categories</th>
<td>
<cfselect bindonload="true" name="varCategory" bind="cfc:cfc.art.GetCategories()"/>
</td>
</tr>
</table>
<cfgrid name="ArtList" bindonload="false" format="html" pagesize="20" striperows="yes" width="700"
bind="cfc:cfc.art.GetArt({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection},{varCategory})">
<cfgridcolumn name="art_id" display="false"/>
<cfgridcolumn name="art_title" header="Title" width="300" select="false" />
<cfgridcolumn name="artist_name" header="Lang" width="50" select="false" />
<cfgridcolumn name="add" header="ADD IT!" width="50" />
</cfgrid>
</cfform>
/*** ART.CFC file contents ***/
<cffunction name="GetCategories" access="remote">
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<cfquery name="data" datasource="art_db">
SELECT art_categories.categoryid,
art_categories.category_name
FROM art_categories
ORDER BY category_name
</cfquery>
<cfloop index="i" from="1" to="#data.RecordCount#">
<cfset result[i][1]=data.categoryid[i]>
<cfset result[i][2]=data.category_name[i]>
</cfloop>
<cfreturn result>
</cffunction>
<cffunction name="GetArt" access="remote" returntype="struct">
<cfargument name="page" type="numeric" required="yes">
<cfargument name="pageSize" type="numeric" required="yes">
<cfargument name="gridsortcolumn" type="string" required="no" default="">
<cfargument name="gridsortdir" type="string" required="no" default="">
<cfargument name="varCategory" type="any" required="yes" default="0">
<cfquery name="data" datasource="art_db">
SELECT art_id,
art_title,
artist_name
FROM art
WHERE categoryid=#varCategory#
<cfif ARGUMENTS.gridsortcolumn NEQ "" and ARGUMENTS.gridsortdir NEQ "">
ORDER BY #ARGUMENTS.gridsortcolumn# #ARGUMENTS.gridsortdir#
<cfelse>
ORDER BY artist_name,art_title
</cfif>
</cfquery>
<cfset queryAddColumn(data, "add", arrayNew(1))>
<cfloop query="data">
<cfset querySetCell(data, "add", "<input value='Add' type='button' onclick='javascript:testit(#module_id#)'>", currentrow)>
</cfloop>
<cfreturn QueryConvertForGrid(data, ARGUMENTS.page, ARGUMENTS.pageSize)>
</cffunction>
Cool. Do folks still want to see me expand on my code to show hooking it up with cfajaxproxy?
Ray, I think it would help provide a total scenario for others looking how to do this. I say this after searching the web for a couple of days on implementing <cfgrid> mixed with form types of uses. There was not a lot being directly said about it and I think others would find it helpful.
Ron
one fix on my post....
<cfset querySetCell(data, "add", "<input value='Add' type='button' onclick='javascript:testit(#module_id#)'>",currentrow)>
should say #art_id# instead of #module_id#
<cfset querySetCell(data, "add", "<input value='Add' type='button' onclick='javascript:testit(#art_id#)'>",currentrow)>
Sorry about that...bad copy/paste from my orig code.
Nice.
You could also just append to the original column the add button:
SELECT art_ID, art_name, '<input type="button" value="Add">' as addButton
FROM artists
thats scratch code not sure exactly what the syntax is for Derby db
The followup:
http://www.coldfusionjedi.c...
Sam, by adding the button as part of your SELECT I don't think you are able to pass the "ART_ID" variable within the javascrip statement...
onclick="javascript:testit(#art_id#)"
He could mod it to use concatation and add the artid value.
@Ray - I put up a similar entry on this exact issue back in November, but took a slightly different approach:
http://blog.cutterscrossing...
When displaying a button in cfgrid does the format have to be ‘html’?
When I us flash as the format I see the string value of the cell, but when I change it to html I get an error saying ‘Attribute validation error for tag CFGRID.The value of the attribute FORMAT, which is currently "html", must be one of the values: APPLET,FLASH,XML.’
What am I doing wrong!!!
Thanks
Flash form grids are a completely different beast. I recommend you don't use them. If you want a Flash based grid, use Flex.
The error you get sounds like you aren't on CF8.