?
Solved

JQGrid and Coldfusion - Can't get display!

Posted on 2014-01-28
10
Medium Priority
?
860 Views
Last Modified: 2014-01-28
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
Comment
Question by:traport
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 5
10 Comments
 
LVL 52

Accepted Solution

by:
_agx_ earned 2000 total points
ID: 39815939
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
 

Author Comment

by:traport
ID: 39815983
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
 
LVL 52

Expert Comment

by:_agx_
ID: 39816068
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
WordPress Tutorial 1: Installation & Setup

WordPress is a very popular option for running your web site and can be used to get your content online quickly for the world to see. This guide will walk you through installing the WordPress server software and the initial setup process.

 

Author Comment

by:traport
ID: 39816205
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
 
LVL 52

Expert Comment

by:_agx_
ID: 39816216
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
 

Author Comment

by:traport
ID: 39816233
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
 
LVL 52

Expert Comment

by:_agx_
ID: 39816335
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
 

Author Comment

by:traport
ID: 39816383
I think it's my min files. I'll take it from here. Really appreciate your help!
0
 

Author Closing Comment

by:traport
ID: 39816387
The whole thread of input was awesome. Thanks so much.
0
 
LVL 52

Expert Comment

by:_agx_
ID: 39816447
Welcome :)
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

JavaScript can be used in a browser to change parts of a webpage dynamically. It begins with the following pattern: If condition W is true, do thing X to target Y after event Z. Below are some tips and tricks to help you get started with JavaScript …
This article discusses how to implement server side field validation and display customized error messages to the client.
The viewer will learn how to dynamically set the form action using jQuery.
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…
Suggested Courses

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question