[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 878
  • Last Modified:

JQGrid and Coldfusion - Can't get display!

I can't for the life of me find what I'm doing wrong in this jqgrid. I've tried to break it down as simply as possible...

Here's my .cfm page:

<head>
<script>
application.cfstatic
		.include('scripts.js');
</script>
<title>Grid Test</title>
 <cfscript>
        param type="string" name="REQUEST.addScriptsHeader" default="";
        param type="string" name="REQUEST.addCSSHeader" default="";
        param type="string" name="REQUEST.addScriptsFooter" default="";
        param type="string" name="REQUEST.addCSSFooter" default="";
        param type="string" name="REQUEST.adder" default="";
        param type="string" name="REQUEST.scriptMinifier" default=".min";
        param type="boolean" name="REQUEST.jqGridLoaded" default=false;

    
        if(!REQUEST.jqGridLoaded){
            savecontent variable="VARIABLES.adder" {
                WriteOutput("<script type='text/javascript' src='/assets/scripts/_lib/jquery/plugins/loadmask-0.4/jquery.loadmask#REQUEST.scriptMinifier#.js'></script>
                    <script type='text/javascript' src='/assets/scripts/_lib/jquery/plugins/jqgrid-4.3.0/js/i18n/grid.locale-en.js'></script>
                    <script type='text/javascript' src='/assets/scripts/_lib/jquery/plugins/jqgrid-4.3.0/js/jquery.jqGrid#REQUEST.scriptMinifier#.js'></script>");
            }
            REQUEST.addScriptsHeader &= VARIABLES.adder;
            savecontent variable="VARIABLES.adder" {
                WriteOutput("<link href='/assets/scripts/_lib/jquery/plugins/loadmask-0.4/jquery.loadmask.css' type='text/css' rel='stylesheet' />
                    <link href='/assets/scripts/_lib/jquery/plugins/jqgrid-4.3.0/css/ui.jqgrid.css' type='text/css' rel='stylesheet' />");
            }
            REQUEST.addCSSFooter &= VARIABLES.adder;
            REQUEST.jqGridLoaded = true;
        }
</cfscript>
</head>

<body>
	<table id="list" class="scroll" cellpadding="0" cellspacing="0"></table>
 		<div id="pager" class="scroll" style="text-align:center;"></div> 
		<div id="mysearch"></div>
</body>

Open in new window


--- Here's my .cfc

<cfcomponent displayname="UserMgr" output="false"> 
  
<cffunction name="getTestUsers" access="remote" output="false" returnformat="json">
    <cfargument name="page" required="no" default="1">
    <cfargument name="rows" required="no" default="10">
    <cfargument name="sidx" required="no" default="">
    <cfargument name="sord" required="no" default="ASC">
    <cfset var q = "">
    <cfquery datasource="#session.currentdsn#" name="q">
    SELECT top 10 id, firstname, lastname
    FROM f_users
    <cfif len(arguments.sidx)>
    ORDER BY #arguments.sidx# #arguments.sord#
    </cfif>
    </cfquery>
    
    <cfreturn queryConvertForJQGRID(q, arguments.page, arguments.rows) />
  </cffunction>
    
  <cffunction name="queryConvertForJQGRID" access="package" returntype="struct" output="no"> 
    <cfargument name="q" type="query" required="yes"> 
    <cfargument name="page" type="numeric" required="no" default="1"> 
    <cfargument name="rows" type="numeric" required="no" default="10"> 
    <cfset var result = structnew()> 
    <cfset var rowStruct = structnew()> 
    <cfset var col = ""> 
    <cfset result.page = arguments.page> 
    <cfset result.total = ceiling(arguments.q.recordcount/arguments.rows)> 
    <cfset result.records = arguments.q.recordcount> 
    <cfset result.rows = arraynew(1)> 
    <cfoutput query="arguments.q" startrow="#(arguments.page-1)*arguments.rows+1#" maxrows="#arguments.rows#"> 
      <cfset rowStruct = structnew()> 
      <cfset rowStruct['id'] = id>
	  <cfset rowStruct['cell'] = arraynew(1)>
      <cfset rowStruct['cell'][1] = arguments.q['id'][currentrow]> 
      <cfset rowStruct['cell'][2] = arguments.q['firstname'][currentrow]> 
      <cfset rowStruct['cell'][3] = arguments.q['lastname'][currentrow]> 
      <cfset arrayappend(result.rows, rowStruct)> 
    </cfoutput>
	<cfset output = SerializeJSON(result)>
	<cfset output = replace(output,'.0','','all')>
	<cfset output = replace(output,'ROWS','rows','all')>
	<cfset output = replace(output,'PAGE','page','all')>
	<cfset output = replace(output,'TOTAL','total','all')>
	<cfset output = replace(output,'RECORDS','records','all')>
	<cfset output = replace(output,'CELL','cell','all')>
    <cfreturn output /> 
  </cffunction> 

</cfcomponent>

Open in new window


Here's my .js

$("document").ready(function() {

		jQuery("#list").jqGrid({
			url:'processor.cfc?method=getTestUsers',
			width:"auto",
			height:"auto",
			datatype: "json",
			colNames:['ContactID','First Name','Last Name'],
			colModel:[
				{name:'id',index:'id', width:55},
				{name:'firstname',index:'firstname', width:200},
				{name:'lastname',index:'lastname', width:250},
				
			],
			rowNum:10,
			rowList:[10,20,30],
			pager: '#pager',
			sortname: 'id',
			viewrecords: true,
			sortorder: "asc",
			caption:"User List"
			});

		});

Open in new window


I'm not getting a display on the front end and when I go to processor.cfc?method=getTestUsers I get:

The value returned from the queryConvertForJQGRID function is not of type struct.

If the component name is specified as a return type, it is possible that either a definition file for the component cannot be found or is not accessible.
 
The error occurred in C:/inetpub/wwwroot/tracitest/processor.cfc: line 17
15 :     </cfquery>
16 :    
17 :     <cfreturn queryConvertForJQGRID(q, arguments.page, arguments.rows) />
18 :   </cffunction>
19 :    

Ugh Please help!
0
traport
Asked:
traport
  • 5
  • 5
1 Solution
 
_agx_Commented:
The problem is pretty much what the error message says.  queryConvertForJQGRID  isn't returning a structure.  The "output" variable contains a string, so the function is actually returning a string, not a structure. Just return the "result " variable instead.

Side note, I notice you've encountered CF's unfortunate habit of converting structure keys to all upper case. If you want to preserve the case of key names (for javascript), use array notation, instead of dot-notation, ie

<cfset result["page"] = arguments.page>
<cfset result["total"] = ceiling(arguments.q.recordcount/arguments.rows)>
... other keys ...

EDIT: Though you don't need the "output" variable anymore, ... if you did, don't forget to VAR scope it too
0
 
traportAuthor Commented:
Hey _agx_,

Thanks for the response. I don't know how to return the result variable versus the structure (and I guess I don't know how to return a structure, either).

What's the benefit to using array notation versus dot notation? Are you saying then case doesn't matter for javascript?

And (20 questions!)... Would you give an example of the VAR scope for output variables and if you could explain why that'd be much appreciated, too.

I'm a homegrown developer so it's people like you who really help me along. Thanks.
0
 
_agx_Commented:
how to return the result variable

Inside your function, you're already creating a structure named "result". All you need to do is return that variable instead of "output":

  <cffunction ....>
      .... existing code
      <!--- return structure instead of "output" variable --->
      <cfreturn result />
  </cffunction>

What's the benefit to using array notation versus dot notation? Are you saying then case doesn't matter for javascript?


No, you were right the first time :) Javascript definitely *is* case sensitive.  That's the reason you need to use array notation. Unfortunately, when you use dot notation, CF ignores whatever case you used and converts everything to upper case:

         <cfset result.page = "something...">
        <!--- serialized as JSON ...  --->
        { PAGE="something..." }

... so your javascript won't work because it's looking for "page" (all lower case).  When you use array notation, CF sends the key name exactly as you entered it (ie all lower case)

         <cfset result["page"] = "something...">
        <!--- serialized as JSON ...  --->
        { page="something..." }



Would you give an example of the VAR scope for output variables and if you could explain why that'd be much appreciated, too.

Any variable used only within the function (ie function local variables) should be VAR scoped.  You're already doing that with the other variables here. Just do the same with "output" at the top of the function:

       <!--- use VAR to put these variables in the local scope --->
       <cfset var result = structnew()>
        ....
       <cfset var output = ""> 

VAR scoping is a complex topic, but an interesting one :) The reason you var scope is - thread safety. In other words, to prevent one thread from messing up the results of another thread. Usually you only encounter thread issues when you're storing components in a shared scope (like application).  That's not the case here ... but it's good to plan ahead and always make code thread safe from the get-go.

Here's a brief blurb about var scoping (or LOCAL-scoping in CF9+):
http://forta.com/blog/index.cfm/2009/6/21/The-New-ColdFusion-LOCAL-Scope

I'm a homegrown developer so it's people like you who really help me along.

Anytime. I always enjoy discussions on "how things work and why" :)
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
traportAuthor Commented:
Thank you. Very insightful answer & help. I'm going to put these things into practice.

For some reason <cfreturn result /> came back with an error Variable result is undefined on processor.cfc and nothing returned in the grid.
0
 
_agx_Commented:
Hm.. that variable is clearly defined. Are you sure you put it in the right function - ie queryConvertForJQGRID?

<cffunction name="queryConvertForJQGRID" access="package" returntype="struct" output="no">
    <cfargument name="q" type="query" required="yes">
    <cfargument name="page" type="numeric" required="no" default="1">
    <cfargument name="rows" type="numeric" required="no" default="10">
   <cfset var result = structnew()>  <!--- **** DEFINED HERE --->
    <cfset var rowStruct = structnew()>
    <cfset var col = ""> 

    <cfset result["page"] = arguments.page>
    <cfset result["total"] = ceiling(arguments.q.recordcount/arguments.rows)>
    <cfset result["records"] = arguments.q.recordcount>
    <cfset result["rows"] = arraynew(1)>


    <cfoutput query="arguments.q" startrow="#(arguments.page-1)*arguments.rows+1#" maxrows="#arguments.rows#">
         <cfset rowStruct = structnew()>
         <cfset rowStruct['id'] = id>
       <cfset rowStruct['cell'] = arraynew(1)>
         <cfset rowStruct['cell'][1] = arguments.q['id'][currentrow]>
         <cfset rowStruct['cell'][2] = arguments.q['firstname'][currentrow]>
         <cfset rowStruct['cell'][3] = arguments.q['lastname'][currentrow]>
         <cfset arrayappend(result.rows, rowStruct)>
    </cfoutput>

   <cfreturn result />
  </cffunction>
0
 
traportAuthor Commented:
I'd incorrectly placed the cfreturn result in the function ABOVE.

Okay so that works to output on the processor.cfc?method=GetUsers page... Great!

Shows: "{"rows":[{"cell":[20,"Christian","Ready"],"id":20},{"cell":[21,"Sean","Louisin"],"id":21},{"cell":[22,"Mike","Coleman"],"id":22},{"cell":[23,"Jim","Studebaker"],"id":23},{"cell":[24,"",""],"id":24},{"cell":[29,"Yancy","Wharton"],"id":29},{"cell":[26,"Donald","Hawkins"],"id":26},{"cell":[30,"Scott","Harvey"],"id":30},{"cell":[31,"",""],"id":31},{"cell":[32,"Dana","Lecroy"],"id":32}],"page":1,"records":7289,"total":729.0}..."

Now, why doesn't that autopopulate a grid on the index.cfm page?
0
 
_agx_Commented:
Not sure. I'll have to find a copy of jGrid and try it.  Do you see any errors in your javascript console (Firebug, etc..)?
0
 
traportAuthor Commented:
I think it's my min files. I'll take it from here. Really appreciate your help!
0
 
traportAuthor Commented:
The whole thread of input was awesome. Thanks so much.
0
 
_agx_Commented:
Welcome :)
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 5
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now