The cfwheels documentation says that for using hasManyRadioButton() the property field is required. But in their example they haven't used property.
Following is the example provided by cfwheels documentation.
<!--- Show radio buttons for associating a default address with the current author --->
<cfloop query="addresses">
#hasManyRadioButton(
label=addresses.title,
objectName="author",
association="authorsDefaultAddresses",
keys="#author.key()#,#addresses.id#"
)#
</cfloop>
Is the property attribute required or not? What is the right convention to use this function?
I believe that the property argument would be required. The example appears to be incomplete.
The docs should probably look something like this:
<!--- Show radio buttons for associating a default address with the current author --->
<cfloop query="addresses">
#hasManyRadioButton(
label=addresses.title,
objectName="author",
association="authorAddresses",
keys="#author.key()#,#addresses.id#",
property="isDefault",
tagValue=true
)#
</cfloop>
Note that I changed the association argument to show that it probably intended to be a join table linking author with address. I also added property and tagValue arguments as well.
In this case, the radio button is setting some value on the child object (in this example, the authorAddress model).
Related
I have a cfselect with bind attribute and the i want to convert that into to the normal select, it also has the onchange attached to it, what kind i do to return it normal jquery or javascript code
here is my code
<cfselect
name="StatusID"
id="StatusID"
bind="cfc:com.getStatus()"
bindonload="True"
value="StatusID"
display="StatusDescription"
selected="#Val(qry.StatusID)#"
data-validation="required"
data-validation-error-msg="Status selection is required."
onChange="CheckActive()" />
for simpler levels, i can do the <select and for the query i can just do a loop over but what about this.
The bind argument on cfselect will invoke that function in your cfc, which will return some result set (Usually json, or a queryobject). That result set will be used to generate the options. Then the "value" attribute specifies which column from the cfc result set will be used in the "value" argument on the resulting "option" elements. likewise, the display argument corresponds to what will be betweeen the options start and end tags. the Selected arugment will determine which option is selected. Ther other arguments pass through to a normal select.
If you want to generate the vanilla select completely on the server side you can do something like this:
<cfscript>
//You can do something like this to get your data from the CFC
//myCom=CreateObject("component","com");
//statuses=myCom.getStatus();
//Since I don't have an example of what your cfc is returning, I'll assume it's a query result set like this
statuses = queryNew("StatusID,StatusDescription","Integer,Varchar",
[
{StatusID=1,StatusDescription="StatusOne"},
{StatusID=2,StatusDescription="StatusTwo"},
{StatusID=3,StatusDescription="StatusThree"}
]);
//also hardcoding this value because I don't have your qry result set
qry = {statusid=2};
</cfscript>
<cfoutput>
<select
name="StatusID"
id="StatusID"
data-validation="required"
data-validation-error-msg="Status selection is required."
onChange="CheckActive()">
<cfloop query="statuses">
<option value="#statuses.StatusID#" <cfif statuses.statusid eq qry.statusid>selected</cfif>>#statuses.StatusDescription#</option>
</cfloop>
</select>
</cfoutput>
If for some reason you actually need to generate the select on the client side via AJAX, then you will need to write some functions in js/jquery that perform the ajax calls to your cfc instead of using the built in bind expression system in coldfusions cfselect. (for example on how to do that see: Calling a CFC function in AJAX/JQuery and Populating selectlist from AJAX call to CFC)
There are also some other libraries that could make this easier like HTMX: https://htmx.org/examples/value-select/
I was curious if there is a way to force a ColdFusion tag to hold an attribute as default, such as the datasource in cfquery.
For example instead of writing
<cfquery datasource="mydatasource">
I can write
<cfquery>
and the system automatically knows that the datasource is "mydatasource".
Would be really cool if this was possible.
It is actually possible for datasource, but not for everything.
You may set a this.datasource="mydatasource" as the default datasource in your Application.cfc
https://wikidocs.adobe.com/wiki/display/coldfusionen/Application+variables
The practical answer to your question are the custom tags. You can extend the features of ColdFusion tags to match your needs.
Taking into example the cfquery tag and wrapping a custom tag around it. Provide all the default values you want for the parameters of the cfquery into the tag's attribute default.
So essentially your custom tag page would be something like:
flexiquery.cfm
<cfif THISTAG.ExecutionMode EQ 'end'>
<cfparam name="Attributes.datasource" default="someDSN">
<cfparam name="Attributes.cacheWithin" default="#CreateTimeSpan(0,6,0,0)#">
<cfparam name="Attributes.maxRows" default="25">
<cfparam name="Attributes.timeOut" default="600">
<!--- some logic you want to perform --->
<cfquery datasource="#Attributes.datasource#"
cacheWithin="#Attributes.cacheWithin#"
maxRow="#Attributes.maxRows#"
timeOut="#Attributes.timeOut#"
<cfoutput>#THISTAG.GeneratedContent#</cfoutput>
</cfquery>
<!--- Caller assignment and other processing --->
</cfif>
And now you can use it and re-use it across your project, the way you wanted and even overriding the value you want to be different:
<cf_flexiquery>
<!--- you query here --->
</cf_flexiquery>
or
<cf_flexiquery maxRows="100" timeOut="1200">
<!--- you query here --->
</cf_flexiquery>
It gives you a fair idea of how to go with it. I have extended the custom tags features to leverage the features of cfhttp, cfpdf, cffile etc.
This is only way you can adopt the flexibility you want with ColdFusion tags and it works perfectly.
I am using CF10. I have a Select:
<cfselect name="company" id="company" query="qcompany" display="placename" value="placeid" queryposition="below">
<option value="0">--Select--
</cfselect>
I have another cfselect that is bound to the first:
<cfselect name="People" bind="cfc:schedule.GetPeopleArray({company})" ></cfselect>
I cannot get the second cfselect to display any results. To test whether or not I am receiving data from my component (which I will display at the bottom), I bound a text box:
<cfinput name="test" bind="cfc:schedule.GetPeopleArray({company})" bindonload="false"/>
This text box is displaying the results of the call to my component every time, but the cfselect never displays anything.
What could I possibly be doing wrong?
I have tried returning arrays and queries from my component. No help. I have tried adding display and value attributes to the second cfselect. No help.
Here is my component:
<cfcomponent output="false">
<cffunction name="GetPeopleArray" access="remote" returnType="array" output="false">
<cfargument name="company" type="string" >
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<cfquery name="qEmployee" datasource="texas" >
SELECT 0 as personid,'Select Person' as fullname,0 as sortorder
UNION
SELECT p.personid ,concat(firstname,' ',lastname) as fullname,3 as sortorder
FROM person p
INNER JOIN placeperson pp
ON p.personid=pp.personid
where personstatus='ACT'
and pp.placeid=#arguments.company#
order by sortorder,fullname
</cfquery>
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#qEmployee.RecordCount#">
<cfset result[i][1]=qEmployee.personid[i]>
<cfset result[i][2]=qEmployee.fullname[i]>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
</cfcomponent>
Ultimately, you may want use jQuery anyway, but FWIW your existing code worked fine with CF10. (The only change was removing the JOIN for simplicity) So either you are using different code, or there is something else going on we are unaware of ..
Truthfully the Ajax functionality does have some "quirks". However, you should not have any problem with a simple case like this. Aside from adding a text field, what other debugging or troubleshooting steps did you perform? What I usually recommend is:
Test the CFC independently first. Access it directly in your browser with a variety of sample values:
http://localhost/path/to/schedule.cfc?method=GetPeopleArray&company=someValue
I did this with the original code and discovered an error occurred when the company value is not numeric, like an empty string. (I suspect that might have been the problem) You can prevent that error by substituting an invalid ID like 0 instead. Note, be sure to use cfqueryparam to prevent sql injection.
AND pp.placeid = <cfqueryparam value="#val(arguments.company)#"
cfsqltype="cf_sql_integer">
Enable the CF AJAX debugger in the CF Administrator. Then append ?cfdebug to your test script so you can view the console and check for problems/errors.
http://localhost/path/to/yourTestForm.cfm?cfdebug
Again, I did this after tweaking the query. But there were no errors. Your existing cfform code worked perfectly.
Usually those two steps are enough to pinpoint any problems. If not, make sure your Application.cfc file (if you are using one) is not interfering with the Ajax request. That is a common gotcha. Test the code in a separate directory that is outside any Application files.
EDIT: Also, you may as well set bindonload="false" for the select list too. Since you do not want to call the function when the page first loads. Only when the user selects something from the list.
I've got a set of processes I frequently do to a model that I keep redoing in the controller, and I'm wondering if there is a way to implement it through a function in the model, so that I can just call the model function pass some parameters and get the right query.
I've got a linked list, and there's a bit of repetition that I want to avoid.
figured it out...
in model:
<cffunction name="getCustomResults" returntype="query">
<cfset all = findAll()>
<!--- do stuff --->
<cfreturn myQuery>
</cffunction>
getting the custom results
<cfset mySelection = model('myModel').getCustomResults()>
if there is a way to do implement it through a function in the model
Can you please tell what stops you from doing exactly this? Simply create CFC like /models/Foo.cfc where foo is name of your model and extend it with methods. Just don't forget to extend the Model.cfc. See this docs section. Inside the model you have this scope which holds all properties.
Question: I have a CFM calling my CFC on the cfform action line:
In my CFC, I have output="false". I am needing the record count sent back to my CFM. When I run my CFM and enter the form info my queries are running successfully, but it is not coming back to my CFM so I can display the proper messages. I just get the CFC page with my record count. Any suggestions? Thanks!
Since there's no code, making a few assumptions here about how you're doing things ....
Don't point to the CFC, point to a CFM page in your <cfform>. (If you omit the action, it'll point back to itself.. I like self-referencing form pages)
In your CFC, return the result struct from your query:
<cfquery datasource="#ds#" name="myQuery" result="myResult">
INSERT INTO myTable .....
</cfquery>
Then either return that entire struct, or just myResult.recordCount:
<cfreturn myResult.recordCount>
Then in your CFM page, you'll access it like so (assuming you're using <cfscript>; similar if you're doing tag-based):
recordsAdded = createObject('component','myFolder.myCFC').insertMethod(form);
I changed the cfform line to this:
....rest of my form
then added these lines to see if the form was submitted and what action is:
<!--- create object for cfc --->
But now, my query is not running....