bind expressions with RemotingService executeEvent

8 views
Skip to first unread message

Chuck Savage

unread,
Jan 13, 2010, 6:18:26 PM1/13/10
to model-glue
Hi,

I'm trying to use a bind with the remoting service, but get the error
values must be a struct. Since bind's use the {} syntax, it says I
must escape any uses of {} that aren't binds. Can anyone lead me to
the right syntax to use this bind?

bind="cfc:mg.RemotingService.executeEvent(eventName='cservice.search',
values={txtSearch@keyup})"

Otherwise I'll probably have to create another function in the
RemotingService cfc that simply passes the arguments to values.

Dan Wilson

unread,
Jan 13, 2010, 8:45:45 PM1/13/10
to model...@googlegroups.com
Chuck.

Would you mind explaining a little more about what you are trying to do?
I'm having a hard time understanding if your question is a Model-Glue question or a question about the bind syntax.


DW




--
Model-Glue Sites:
Home Page: http://www.model-glue.com
Documentation: http://docs.model-glue.com
Bug Tracker: http://bugs.model-glue.com
Blog: http://www.model-glue.com/blog

You received this message because you are subscribed to the Google
Groups "model-glue" group.
To post to this group, send email to model...@googlegroups.com
To unsubscribe from this group, send email to
model-glue+...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/model-glue?hl=en



--
“Come to the edge, he said. They said: We are afraid. Come to the edge, he said. They came. He pushed them and they flew.”

Guillaume Apollinaire quotes

Chuck Savage

unread,
Jan 14, 2010, 1:14:15 PM1/14/10
to model...@googlegroups.com
Sure,

I'm trying to execute this form in MG.

<cfform name="frmList">
  <cfinput name="txtSearch" type="text" value="">
  <cfinput name="txtResult" type="text"
  bind="cfc:mg.RemotingService.executeBind(eventName='cservice.search', values={txtSearch@keyup}, table='user')">
</cfform>

I added this function to RemotingService.cfc, because the second argument to executeEvent has to be a struct, and from my understand of that bind statement, I can't do dynamic struct creation.

<cffunction name="executeBind" output="false" access="remote" returntype="struct">
  <cfargument name="eventName" type="string" required="true" />
  <cfargument name="returnValues" type="string" required="false" default="" />
   
  <cfreturn executeEvent(arguments.eventName, arguments, arguments.returnValues) />
</cffunction>


I was just asking if anyone has experience using MG and bind statements via the RemotingService.cfc.

At the moment I get the error that RESULT is undefined in LOCAL.

I'm trying to figure that out.




--
Chuck Savage
http://SeaRisen.com

Chuck Savage

unread,
Jan 14, 2010, 1:33:56 PM1/14/10
to model...@googlegroups.com
Well I found a bug with MG's AbstractRemotingService.cfc

ExecuteEvent() returns local.result, but if you don't define any returnValues, result is never set.  And returnValues' default value is an empty string, so no returnValues is legitimate.

Dan Wilson

unread,
Jan 14, 2010, 1:40:25 PM1/14/10
to model...@googlegroups.com
OK, I've checked in a fix that defines local.result as a struct.

DW

--
Model-Glue Sites:
Home Page: http://www.model-glue.com
Documentation: http://docs.model-glue.com
Bug Tracker: http://bugs.model-glue.com
Blog: http://www.model-glue.com/blog

You received this message because you are subscribed to the Google
Groups "model-glue" group.
To post to this group, send email to model...@googlegroups.com
To unsubscribe from this group, send email to
model-glue+...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/model-glue?hl=en

Chuck Savage

unread,
Jan 14, 2010, 1:41:45 PM1/14/10
to model-glue
What's the proper return value? I don't think I want a name/value
pair
returning to the bind, I just want a value and was thinking I'd use
the view
result.

Should I make a similar executeBind in AbstractRemotingService, but if
I
wanted to bind to a cfgrid vs the above text box, what is the proper
return?

Dan Wilson

unread,
Jan 14, 2010, 1:54:51 PM1/14/10
to model...@googlegroups.com
I think you are misunderstanding how the remoting works. The intent is to allow remote access to fire off Model Glue events and return Model Glue event values. During the course of processing an event handler, any number of values might be placed into the event. As such, when you want a value out of the event you must ask for it by name:

event.getValue("food") 

Then the event will return that value to you. This is because the event stores a whole bunch of values in it and they are keyed as name=value, just like a struct or collection.

So, with the RemotingService, you have access to any event handler and can get any number of event values out of the event. The datastructure that mimics the event, is a struct, thus the RemotingService will return a struct for you. Once you have the data, you will have to deal with that data and get out what you need. This is a concern of your individual application, not the RemotingService.

DW



--
Model-Glue Sites:
Home Page: http://www.model-glue.com
Documentation: http://docs.model-glue.com
Bug Tracker: http://bugs.model-glue.com
Blog: http://www.model-glue.com/blog

You received this message because you are subscribed to the Google
Groups "model-glue" group.
To post to this group, send email to model...@googlegroups.com
To unsubscribe from this group, send email to
model-glue+...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/model-glue?hl=en

Chuck Savage

unread,
Jan 14, 2010, 2:06:38 PM1/14/10
to model-glue
Right I understand that.

But with a Bind expression, you want only a single value returned. I
got my code to work, but had to create these functions, and modify my
form like...

<cfform name="frmList">
<cfinput name="txtSearch" type="text" value="">
<cfinput name="txtResult" type="text"

bind="cfc:mg.RemotingService.executeBindEvent


(eventName='cservice.search', values={txtSearch@keyup})">

</cfform>

The RemotingService has this new function,

<!--- pass in your values is name=value pairs to the function, all are
passed as the
arguments structure to the super.executeBindEvent() --->
<cffunction name="executeBindEvent" output="false" access="remote"
returntype="any">


<cfargument name="eventName" type="string" required="true" />

<cfargument name="returnValue" type="string" required="false"
default="result" />

<cfreturn super.executeBindEvent(arguments.eventName, arguments,
arguments.returnValue) />
</cffunction>


In AbstractRemotingService.cfc I added this function,

<cffunction name="executeBindEvent" output="false" access="remote"
returntype="any">


<cfargument name="eventName" type="string" required="true" />

<cfargument name="values" type="struct" required="false"
default="#StructNew()#"/>
<cfargument name="returnValue" type="string" required="false"
default="result" />
<cfset var local = StructNew()/>

<!--- For Javascript post calls to the service --->
<cfif cgi.request_method eq "post">
<cfset arguments.values = duplicate(form)/>
</cfif>

<cfset local.event = getModelGlue().executeEvent
(argumentCollection=arguments) />

<cfset local.result = local.event.getValue(returnValue) />

<cfset resetCFHtmlHead() />
<cfreturn local.result />
</cffunction>

At the moment, the form just echo's the typed text via my controller's
code, but it could be made to do lookups in the database which is to
come and via a bind to a cfgrid. More testing to come.

Just try my code, its self explanatory. If what I've done can be done
with existing MG code let me know, but I can't use a struct in a
<cfinput> bind expression and I can't use a struct in the return value
either.

Dan Wilson

unread,
Jan 14, 2010, 2:11:26 PM1/14/10
to model...@googlegroups.com
Chuck, you should not be editing the AbstractRemoteService. That is an internal framework object and should be left alone. There is never any reason to edit any internal framework object. 

Secondly, while you are on the right track with how to get out the value you need, you are doing it in the wrong place. You need to handle this in a different place,possibly in your RemoteService, but definitely not in the AbstractRemoteService.

You can make any number of CFCs that extend the AbstractRemoteService, and you should make your customizations in there. That way the specific behavior and intelligence needed for your application, stays in your applicaiton. It is not the job of the AbstractRemoteService to know, or care about who will be consuming the data and any specific formatting or interpretation needed by a data consumer. 


DW






--
Model-Glue Sites:
Home Page: http://www.model-glue.com
Documentation: http://docs.model-glue.com
Bug Tracker: http://bugs.model-glue.com
Blog: http://www.model-glue.com/blog

You received this message because you are subscribed to the Google
Groups "model-glue" group.
To post to this group, send email to model...@googlegroups.com
To unsubscribe from this group, send email to
model-glue+...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/model-glue?hl=en

Chuck Savage

unread,
Jan 14, 2010, 2:34:23 PM1/14/10
to model-glue
Ok, I just thought it was a behavior that MG would want, the ability
to work with native ColdFusion bindings. I'm working from CF
Developers guide ~page 975

Ultimately it doesn't matter to me, as you say I can make my own cfcs.

Dan Wilson

unread,
Jan 14, 2010, 2:45:27 PM1/14/10
to model...@googlegroups.com
The original email you sent referred to a bug with the AbstractService and it just isn't a bug that a binding call needs a little extra formatting. I'd call it an enhancement request, if anything.

We are always looking for ways to improve Model Glue and if you've got something that makes development in ColdFusion easier, then we are all ears. If you want to put together a small sample application that shows the before and after, we'll certainly take a look at it internally.

From my limited experience with bindings and the ColdFusion Ajax stuff, I almost always have to add proxy function to massage the data or deal with some post-retrieval processing, event management or something. 

DW
 


--
Model-Glue Sites:
Home Page: http://www.model-glue.com
Documentation: http://docs.model-glue.com
Bug Tracker: http://bugs.model-glue.com
Blog: http://www.model-glue.com/blog

You received this message because you are subscribed to the Google
Groups "model-glue" group.
To post to this group, send email to model...@googlegroups.com
To unsubscribe from this group, send email to
model-glue+...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/model-glue?hl=en

Chuck Savage

unread,
Jan 14, 2010, 8:12:56 PM1/14/10
to model...@googlegroups.com
The bug you fixed, was that local.result had no value if returnValues was an empty string.

The rest is an enhancement request.  I'm using it just fine, for example with this cfgrid.

  <cfgrid name="gridResults" bindonload=true format="html" width="99%" striperows=true
  pagesize="20" selectOnLoad=false
  bind="cfc:mg.RemotingService.executeBindEvent(
      eventName='#searchEvent#', text={txtSearch@keyup}, category={cbCategory},
    page={cfgridpage},
    size={cfgridpagesize},
    column={cfgridsortcolumn},
    direction={cfgridsortdirection}
    )">
      <cfgridcolumn name="id"  header="Customer Number" />
      <cfgridcolumn name="name" header="Name" />
      <cfgridcolumn name="username" header="Username" />
      <cfgridcolumn name="email" header="Email Address" />
      <cfgridcolumn name="dateadded" header="Date Added" />
  </cfgrid>

I just could not do that with executeEvent() as it currently exists.  If you want to implement what I posted earlier, go for it, it works as is.

My controller code, if anyone wants a peek, looks like,

    <cfset var table = event.GetArgument('table')>
    <cfset var gateway = beans.reactor.createGateway(table)>
    <cfset var text = event.GetValue('text')>
    <cfset var field = event.GetValue('category')>
    <cfset var page = event.GetValue('page')>
    <cfset var size = event.GetValue('size')>
    <cfset var column = event.GetValue('column')>
    <cfset var direction = event.GetValue('direction')>
    <cfset var result = StructNew()>

    <cfset result.query = gateway.search(field, text, column, direction, page, size)>   
    <cfset result.TotalRowCount = gateway.numberOfRecords(field, text)>

    <cfset event.SetValue('result', result)>

The gateway.search() and the gateway.numberOfRecords() are custom functions, since I couldn't find a way to do search's in reactor, and the numberOfRecords() is needed for the cfgrid to know how many records would be returned were I not using the LIMIT clause in my mysql statement in search().

Chuck Savage

unread,
Jan 15, 2010, 9:21:35 PM1/15/10
to model-glue
Dan,

Here's an example. I didn't want to post this in that trak ticket.

From the translator example, I modified two files to make this.
frmPhrase.cfm and Controller.cfc

First the form,

<cfset translateEvent = event.GetValue('xe.translate')>

<cfform name="frm">
<p>
Enter text to translate: <cfinput type="text" name="txtPhrase"
value="" />
Translation: <cfinput type="text" name="result"
bind="cfc:translator.RemotingService.executeBindEvent(
eventName='#translateEvent#', phrase={txtPhrase@keyup})" >
</p>
</cfform>

The controller function

<cffunction name="TranslatePhrase" access="public" returntype="void"
output="no">
<cfargument name="event" type="any">

<cfset var phrase = arguments.event.getValue("phrase") />
<cfset var result = beans.translator.translate(phrase) />

<cfif not len(trim(phrase))>
<cfset arguments.event.SetValue("result", "Please enter a phrase
to translate.")>
<cfelse>
<cfset arguments.event.SetValue("result", result)>
</cfif>

<cfset arguments.event.addTraceStatement("TranslatePhrase
Results", result) />

</cffunction>


I tried using a bind on a cfdiv, but it kept sending two commas even
if the text box was empty. I couldn't figure it out. As a result,
the translation text box is too short to display the full error
message, but at least you can see it working.

The code for the eventBindEvent() in RemotingService.cfc is the same
as posted above.

Ezra Parker

unread,
Jan 16, 2010, 4:12:49 PM1/16/10
to model...@googlegroups.com
Hi Chuck,

This may not be an approach you wish to take, but it is possible to
achieve the same result without modifying the RemotingService by using
a cfajaxproxy bind instead:

<cfset translateEvent = event.GetValue('xe_translate')>

<cfajaxproxy bind="url:RemotingService.cfc?method=executeEvent&returnformat=json&eventName=#translateEvent#&returnValues=translatedPhrase&phrase={txtPhrase@keyup}"
onsuccess="setResult" />

<script type="text/javascript">
<!--
function setResult(returnValue) {
document.getElementById('result').value = returnValue.translatedPhrase;
}
//-->
</script>

<cfform name="frm">
<p>
Enter text to translate: <cfinput type="text" name="txtPhrase" value="" />

Translation: <cfinput type="text" name="result" id="result" />
</p>
</cfform>

--
Ezra Parker

Chuck Savage

unread,
Jan 16, 2010, 5:19:12 PM1/16/10
to model...@googlegroups.com
Thanks Ezra,

That's the first example I've seen.  Though its not a straight up bind, with result handled by coldfusion, but thanks for the example.

I was going for a complete bind, just for curiosity sake.  In the end I probably cannot avoid javascript.  My next curiosity is handling dynamic cfdiv's.  ColdFusion docs suggest that they can do about anything via the cfdiv's binds, but I haven't figured it out yet.


On Sat, Jan 16, 2010 at 2:12 PM, Ezra Parker <ez...@cfgrok.com> wrote:
Hi Chuck,

This may not be an approach you wish to take, but it is possible to
achieve the same result without modifying the RemotingService by using
a cfajaxproxy bind instead:

<cfset translateEvent = event.GetValue('xe_translate')>

<cfajaxproxy bind="url:RemotingService.cfc?method=executeEvent&returnformat=json&eventName=#translateEvent#&returnValues=translatedPhrase&phrase={txtPhrase@keyup}"
onsuccess="setResult" />

<script type="text/javascript">
<!--
function setResult(returnValue) {
       document.getElementById('result').value = returnValue.translatedPhrase;
}
//-->
</script>

<cfform name="frm">
<p>
 Enter text to translate: <cfinput type="text" name="txtPhrase" value="" />
 Translation: <cfinput type="text" name="result" id="result" />
</p>
</cfform>

--
Ezra Parker

Reply all
Reply to author
Forward
0 new messages