Knowing when the cfform data arrives
111 comments Posted by: LauraSo you thought that onload would fix all of your problems. Say you wanted to select an item in the datagrid as soon as the form "loaded". Great, you may have though, I’ll use onload. If you did, you may have discovered that the form loads, and then the data loads, and most likely, when you run your onload function the data has not yet arrived. So how do you know when it does?
Some components (for some reason the tree doesn’t want to do it) trigger an event when their dataProvider changes. That event is called “modelChanged”. In order to be notified when that happens, add the following to your onload function:
var listener:Object = {};
listener.modelChanged = function(evt):Void {
alert('Data loaded');
<!--- do whatever you need to do when the data loads --->
}
myGrid.addEventListener('modelChanged',listener);
This will work for datagrids and selects. To remove a listener that you no longer need:
myGrid.removeEventListener('modelChanged',listener);
I’ll show three different uses of this on a datagrid: selecting the first item when the data loads, clear the grid to use the filter shown in Filtering a grid as you type – using functions and load an empty grid and populate it with remoting instead.
Selecting the first item
<cfform name="myForm" format="flash" onload="onFormLoad()">
<cfformitem type="script">
<!--- onload function --->
function onFormLoad(){
var listener:Object = {};
//put the controls in scope to avoid calling _root
var contactList:mx.controls.DataGrid = contactList;
listener.modelChanged = function(evt):Void {
alert('Data loaded... select first item');
<!--- remove listener, so that we are not longer notified of model changes --->
contactList.removeEventListener('modelChanged',listener);
<!--- select first item --->
if (contactList.dataProvider.length){
contactList.selectedIndex = 0;
}
}
contactList.addEventListener('modelChanged',listener);
}
</cfformitem>
<cfgrid name="contactList" query="contactsQuery" rowheaders="false">
<cfgridcolumn name="name" header="Employee Name">
<cfgridcolumn name="gender" header="Gender">
<cfgridcolumn name="age" header="Age">
</cfgrid>
</cfform>
Run the filter function
This is a slightly changed version of the applyFilter function. I also changed its name to better describe what it does now
<cfform name="myForm" format="flash" onload="onFormLoad()">
<cfformitem type="script">
<!--- onload function --->
function onFormLoad(){
var listener:Object = {};
//put the controls in scope to avoid calling _root
var contactList:mx.controls.DataGrid = contactList;
listener.modelChanged = function(evt):Void {
alert('Data loaded... clear datagrid until department is selected');
<!--- remove listener, so that we are not longer notified of model changes --->
contactList.removeEventListener('modelChanged',listener);
<!--- empty search, should return no value --->
search('',contactList,[]);
}
listener.search = search;
contactList.addEventListener('modelChanged',listener);
}
<!--- search function --->
function search( term:String, grid:mx.controls.DataGrid, columns:Array ):Void {
var filterTerm:String = term.toString().toLowerCase();
if(_global.unfilteredData[grid.id] == undefined){
if (_global.unfilteredData == undefined){
_global.unfilteredData = {};
}
_global.unfilteredData[grid.id] = grid.dataProvider.slice(0);
}
if(filterTerm.length > 0) {
var filteredData:Array = [];
for(var i = 0; i< _global.unfilteredData[grid.id].length; i++) {
var item:Object = _global.unfilteredData[grid.id][i];
var added:Boolean = false;
for(var j = 0; j< columns.length; j++){
if(!added){
var value:String = item[columns[j]].toString().toLowerCase();
if(value.indexOf(filterTerm) != -1) {
filteredData.push(item);
added = true;
}
}
else {
break;
}
}
}
grid.dataProvider = filteredData;
}
else {
grid.dataProvider = [];
}
}
</cfformitem>
<cfformgroup type="horizontal">
<cfgrid name="departmentList" query="departmentsQuery" onchange="search(departmentList.selectedItem.id, contactList, ['department'])">
<cfgridcolumn name="name" header="Department">
</cfgrid>
<cfgrid name="contactList" query="contactsQuery">
<cfgridcolumn name="name" header="Employee Name">
<cfgridcolumn name="gender" header="Gender">
<cfgridcolumn name="age" header="Age">
</cfgrid>
</cfformgroup>
</cfform>
Load it with remoting
<cfform name="myform" height="250" width="400" format="Flash" timeout="300" onload="onFormLoad();">
<cfformitem type="script">
function onFormLoad(){
var listener:Object = {};
//put the controls in scope to avoid calling _root
var getData:Function = getData;
var contactList:mx.controls.DataGrid = contactList;
listener.modelChanged = function(evt):Void {
alert('Empty data loaded... calling remoting');
<!--- remove listener, otherwise we will enter into an infinite loop --->
contactList.removeEventListener('modelChanged',listener);
getData();
}
contactList.addEventListener('modelChanged',listener);
}
function getData():Void{
<cfoutput>
//create connection
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection( "http://#cgi.HTTP_HOST#/flashservices/gateway/");
//declare service
var myService:mx.remoting.NetServiceProxy;
</cfoutput>
var responseHandler:Object = {};
//put the controls in scope to avoid calling _root
var contactList:mx.controls.DataGrid = contactList;
responseHandler.onResult = function( results: Object ):Void {
//when results are back, populate the cfgrid
contactList.dataProvider = results;
mx.managers.CursorManager.removeBusyCursor();
}
responseHandler.onStatus = function( stat: Object ):Void {
//if there is any error, show an alert
alert("Error while calling cfc:" + stat.description);
mx.managers.CursorManager.removeBusyCursor();
}
//get service, make sure you write the correct path
myService = connection.getService("flashRemotingResponder", responseHandler );
mx.managers.CursorManager.setBusyCursor();
//make call
myService.getMembers();
}
</cfformitem>
<cfgrid name="contactList">
<cfgridcolumn name="name" header="Name" />
<cfgridcolumn name="age" header="Age" />
<cfgridcolumn name="gender" header="Gender" />
</cfgrid>
</cfform>
Category: CFForm | ColdFusion |
111 Comments so far
Write yours<cfformitem type="script">
<!--- onload function --->
function onFormLoad(){
var listener:Object = {};
var indexnum = '#url.indexnum#';
//put the controls in scope to avoid calling _root
var da_wkbk:mx.controls.DataGrid = da_wkbk;
listener.modelChanged = function(evt):Void {
alert(indexnum);
<!--- remove listener, so that we are not longer notified of model changes --->
da_wkbk.removeEventListener('modelChanged',listener);
<!--- select item --->
if (da_wkbk.dataProvider.length){
da_wkbk.selectedIndex = indexnum;
da_wkbk.vPosition = indexnum;
}
}
da_wkbk.addEventListener('modelChanged',listener);
}
</cfformitem>
I'm trying to dynamically select a grid row based on url.indexnum.
If I hard code it like this it works:
da_wkbk.selectedIndex = 50;
da_wkbk.vPosition = 50;
I haven't tested your code, but I first glance I notice you didn't assign a datatype to your indexnum variable. AS2.0 has strict datatyping so you probably need:
var indexnum:Number = <cfoutput>#url.indexnum#</cfoutput>;
On a side note, beware of using CF variables in your AS functions. Every time the variable changes, CF recompiles the entire form before sending it to the user.
Let us know if the change works.
grid.vPosition = indexnum;
This will scroll the grid onload so that the selectedIndex is the top item in the grid (if the selectedIndex is not visible in the grid.
One thing I used this for was to replace the simple bind on the label property of the base panel. I use the label to display record count info for a grid, but conditions around multiple binds in the label field was getting tricky with syntax.
Finding modelChanged here, I changed to the modelChanged and cellPress events for the grid to populate a hidden textBox and bind the label to that.
More complicated for a simple thing, but if you clear a grid and there is no longer a selectedItem or Index available, the label bind just says 'undefined'.
Anyway, cheers!
This just started recently but I wonder if you've run into this problem. I wish I could provide a screenshot but this forum doesn't allow that. Nothing I have found in any documentation covers this, but I have noticed that it only occurs when I am running a template that uses <cfpop> ...
Your problem is probably more complex than this, but remember that you can use {(myGrid.selectedItem != undefined)?myGrid.selectedItem.myColumn:'any default'} for binding to remove the undefined.
You can leave 'any default' blank '' if you don't want to show anything.
BM,
I've never seen that. But I don't see how cfpop would make any difference in the rendered html. Try using different names for your forms and see if it helps.
Could you clarify what you mean by...
"On a side note, beware of using CF variables in your AS functions. Every time the variable changes, CF recompiles the entire form before sending it to the user..."
And maybe give an example of how to better use CF variables in actionscript to avoid this issue.
Thanks
Any ActionScript code we add to a cfform becomes part of the generated file. If anything in the generated file changes, then the form must be recompiled. Having a variable that changes in every request will make the form recompile each time, making the form slow to load, showing a blank screen (not the preloader).
As a best practice, only have variables inside the controls, never in the ActionScript (unless it is a variable that never changes, such as a domain or script name)
Thanks for the direct answer... could you give an example of 'only having variable inside controls'
I'm not sure what you mean by that...
Thanks
If I understand Laura correctly, she is saying that it is OK to use variables in a form item such as a text box.
Ex. <cfinput type="text" name="#url.variable#">
Not in the actionscript - which would be like this:
<cfinput type="text" name="textbox1" onchange="var test = '#url.variable#'; if (test == "testing"){alert('test');}"
Yes, that is what I meant. Except that todd's first example will also cause a recompile :(
Variables should only go in the control's data place holder, most, if not all, of the other attributes will cause the source to change. If it is a text input, then the "value" can, and most likely will, be a variable, for textareas, the value inside the tags can be a variable, for grids and selects, the query's data can change every time and it would be fine. You get the idea.
That also goes for <cfif> statements or loops that change what controls are included in the form or anything else that is not data.
When in doubt, run your page and look at the source, you will find the name of the generated swf, something like 1913161393.mxml.cfswf then change the variable's value and refresh. If the number changes, then it was recompiled.
I found a pretty cool way to use variables within my as that won't cause a recompile. It can only be used in certain scenarios though.
On the main page of my site I set a shared object based on user selections. Than as the user navigates to a separate page, I reference that shared object to get the dynamic variable that I may use in a remoting call or whatever else I need to. It works pretty great!
I have another question - If you could help I would greatly appreciate.
I have a custom tag built to export a cfgrid to excel. It works perfectly - until and unless a grid row is selected. Once a grid row is selected, certain columns in that row simply disappear from my dataProvider - the weird thing is that it is only columns 1, 2, 3, & 5 - cols 4, 6, & 7 are fine.
Any ideas???
I ran into this exact same problem a month or so back. Rather than making you feel the same pain, I'll just give you the answer without making you search for it.
You have a panel:
<cfFormGroup type="panel"....
underneath that, have an invisible checkbox:
<cfinput type="checkbox" name="chk_displayPanel" checked="no" visible="no" label="" />
in the opening panel tag, place these attributes:
<cfFormGroup type="panel" visible="{chk_displayPanel.selected ? true : false}" height="{chk_displayPanel.selected ? SOME_HEIGHT_HERE : -6}" label="SOME_LABEL_HERE" />
notice the dynamic height tag; when you make a form element invisible, it just...goes away, but the space is still not available (you would just have a big empty white space where the panel used to be). However, by making the panel's height a negative 6, and then making it invisible, you have in essence made it disappear.
What you would then do to make the panel appear/disappear is have a button with something like the following (anything with an onchange/onclick event would do the trick, I just happened to pick a button):
<cfinput type="button" name="but_displayPanel" value="Display Panel" onClick="changePanelState();" />
and, finally, have a function something like this:
<cfFormItem type="script">
function changePanelState():Void {
if (_root.chk_displayPanel.selected) {
_root.chk_displayPanel.selected = false;
_root.but_displayPanel.label = "Display Panel";
} else {
_root.chk_displayPanel.selected = true;
_root.but_displayPanel.label = "Hide Panel";
}
</cfFormItem>
I am 100% positive that this can probably be condensed down some, but this is how I got it resolved. I use it all over the place now. If you have any problems, post something here and someone will be able to lend you a hand.
Is there any way that I can get my session?
1) How can I re-populate after the datagrid loaded? Should I clear the datagrid first before re-populate thru the remoting?
2) I'm trying to select the first item after it populated from the remoting. But I could not get it to work by just calling the onFormLoad().
I would appreciate if you could help me with the following:
I have been using a CFC to handle a grid update as per the shipped docs of CF7 from a flash form using a full submit, which then recompiles the flash form after submission. Its works fine. What i have now do is use actionscript and a facade to call a cfc to handle all calls and submissions via remoting.
My question is that I don’t know the actionscript that handles a call via remoting to my facade. I currently create a object that then handles the variables to the function call via remoting for all other form submissions and selects calls.
Have no idea how to handle grid updates etc in actionscript. Please you help me. I have an application which makes extensive use of grids, selects, text fields etc. The grids evade me.
Kind Regards
Ok, it's getting near the end of my working week, so if anyone has time to test this further before Monday morning, and get back to confirm my initial tests, i'd be greatful. I haven't read this anywhere else yet, so my apologies if this has been covered.
If you write your code in include files with the .as extension, you can freely use the reserved words. i.e. I have this code in a .as file, included onload, and it works perfectly!
var myDate: Date = new Date();
var date_str:String = (myDate.getDate()+"/"+(myDate.getMonth()+1)+"/"+myDate.getFullYear());
alert(date_str);
If this is used directly in the cfm you get the error. Also, this is within a function, so the code isn't being run straight away.
Obviously the cf server isn't looking at all the code in the include file, and the flash player is happy to run it once it's compiled.
My knowledge on how this works is limited, but if anyone else can test this and get back to me, much appreciated.
We have an application that is a form group of tabs with each tab having n number of children. Also, the parents can be unlimited. That was the problem. After the second tab children grids loaded the 32k limit was reached.
I am using the filter as you type function from this site and I did some reading on this functionality also and had a brain ****. So, I combined elements of the two scripts and now have a very unelegant solution that causes absolutely no hit against performance.
Yes, feel free to tell me the code is a bit clunky. I have no problem with that not being a flash developer. But if it works for me maybe you'll get something out of it.
Here is the code I use:
First, the two functions rewritten from here:
<cfsavecontent variable="onLoad1">
Grid_Sales1.dataProvider.removeAll();
</cfsavecontent variable="onLoad1">
(with the number iterating through a loop that creates the grids)
<cfsavecontent variable="binding1">
{(trigger1.text != '') ? trigger1.dispatchEvent({type:'change'}) : 'init'}
</cfsavecontent>
(again, the functions are numbered with a loop that creates the affected grid)
And the last form element in the group is:
<cfinput type="text" enabled="yes" visitle="false" name="trigger8" value="init" onchange="#onLoad1#" bind="#binding1#">
Used in conjunction with the filter as you type functionality it loads three main tabls with three children each with 300 or more records in each child grid.
Yesterday, without this code, I could only load two of the main tabs with children before it died with the 32k limit error. Today, three main tabs with three children and 300 or more records in each child.
Now, I'm NOT a flash programmer so don't hold me to this and please test for yourself. But I just thought I'd share with you since I've gotten a lot of help reading these posts.
Finished till Monday. So far I created a new Array object, and created a new date onject which I used to pass a date the the .selectableRange (which should only take a date object) successfully.
var myDate: Date = new Date();
myDate.setFullYear(2005, 12, 25);
_root.leavingDate.selectableRange = {rangeStart: myDate};
Happy Days... With the creation of objects and the apparent ability to write my own classes now... things a relooking up. (I haven't tried this with the updater yet, this was all done in a _global function held in a .as file called from the onload workaround.
If anyone else trys this, let me know how you get on.
How do you include a .as file at load time?
2nd Q:
I'm dynamically building the columsn in my data grid. I want some of them to format my numbers as currency, withthe currency symbol, 1000s seperators etc. Easy if I make the columsn in CF, but how do I do it from actionscript? Docs suggest building a cell renderer, but I suspect there is something already present in the Flex lib that I can use instead???
<cfformitem type="script">
#include "path/file.as" (note, no ';' required.)
</cfformitem>
How do you submit datagrid changes via remtoing to a CF CFC? I dont know the action script or how to loop corectly to get the required column data that has been edited.
I get it to work with a submitForm(), to CFC. Need flash remoting to do the work without having to build the flash form again...
Pls help... thanx
for a cfselect, you only need to change this:
var contactList:mx.controls.DataGrid = contactList;
to this:
var contactList:mx.controls.ComboBox = contactList;
but really the cfselect always loads with the first item selected. If what you want is to run the filter after the data in the select/grid loads, you need to use the same code in the second example and change this:
search('',contactList,[]);
to the filter of your select, something like:
search(mySelect.selectedItem.data,myGrid,['myColumnToFilterOn']);
Remember to also add
var mySelect:mx.controls.ComboBox = mySelect;
You can maybe add the search code in both modelChanged functions (select and datagrid) in case they do not load at the same time.
<cfsavecontent variable="filterGrid">
if(_global.arrClinics == undefined) _global.arrClinics = clinicList.dataProvider.slice(0);
var arrClinics = _global.arrClinics;
var arrDisplay:Array = [];
var fortext = forInput.text.toLowerCase();
var selected = column.selectedItem.data;
for(var i = 0; i < arrClinics.length; i++)
{
if(arrClinics[i].Status == status.value || status.value == 'All')
{
if(arrClinics[i][selected].toString().substr(0,fortext.length).toLowerCase() == fortext)
{
arrDisplay.push(arrClinics[i]);
}
}
}
clinicList.dataProvider = arrDisplay;
recordCount.text = arrDisplay.length;
</cfsavecontent>
I think I could use your example with the filter function to show active records on load and then also use my cfsavecontent filter which is in the onchange of the cfselect and search input, but this doesn't seem as efficient as one filter function or cfsavecontent tag. I hope this makes sense. Thanks for all the great examples. I really appreciate your willingness to share your expertise.
How can I select the first item AFTER it done loading with remoting?
Thanks
Im struggling with a loop over an editable cfgrid that consists of 5 gridColums and at times up to 500 records plus. Two of the columns are set to boolean which can be checked or unckecked. I would like to only loop over the two boolean columns and then submit those columns to a update updateGrid=
function(args:Object){
// my code here to call make a remoting call to a facade.cfc
}
I just cant seem to get the loop to work, even if I try submit all the columns. The examples show editing and updating a grid on the clients side( eg: filtering etc.
What is the actionscript code to to this please. I have been stuck for days now. Please help.
I manage to update a grid with submitForm(); which the recompiles the submitted form to cfc. I just cant seem to get the code correct.
Kind regards
I have a quite similar problem as one of my pre-posters.
I want to filter my datagrid on things which are selected in some cfselects.
It works find for all my select boxes and their onChange methods. But I want the datagrid to be filtered initially to not display all items and just the preselected one's.
To filter you just have to call my funtion "dgFilter()". But if I insert this function call in one of your examples above (onFormLoad function), this does not work, I'll always get unfiltered data.
Anybody who can help me?
Thanks,
Fritz
Im not sure if this will be any help.But what you need to do is pass the dataprovider only the selected columns that you have filtered back to the grid. To do this you need to loop over the columns that you want. If you go to "ColdFusion Flash Forms Macromedia Developer Center article" all select cooments you will see I have posted a question relationg to remoting with actionscript that selects only the columns I want to pass as arguments to my cfc component. I have a gris with 6 columns but only select three of the 6.
Hope this helps..
the filter casting a "string", but it's mixed 1 with 13. How apply a exact, numeric filter?
Thanks,
Marco
if(value.indexOf(filterTerm) != -1) {
if(value == filterTerm) {
filteredData.push(item);
added = true;
}
}
but the contactList grid is Virtual!.
In fact if the selectmode is set to "edit", no array returned on the form submit.
Help me!
Marco
you can use this for exact matches
if(value == filterTerm) {
filteredData.push(item);
added = true;
}
As it has been explained in this post:
http://www.asfusion.com/blog/entry/filtering-a-grid-as-you-type---using
this function does not work for editable grids.
Thanks for all your hard work with this incredible stuff.
I have one question which I've been working on for the past 3 hours.
I have followed your code for populating a grid using remoting when the form loads. However, I would also like to apply a filter as you type function to the grid. Everytime I try and filter it, all the data disappears from the grid. Sorry if this has been answered already - I've looked around for an answer, but my heads too frazzled now!!
Thanks.
Post your filtering code - it's probably something simple. Are you using toLowerCase()? Sometimes I forget to do that.
Todd
When setting the data with remoting, use
contactList.dataProvider = results.items;
instead of
contactList.dataProvider = results;
That should solve your problem unless you try to use the filter before the data gets from the server.
Todd, I did have toLowerCase() in the code - I always used to forget that, so now i make a point of checking that first!
Laura... that did the trick! How long have you been using actionscript? I need to download your brain!
Thanks again both of you!
How do I get it so that if I clear the search term field after filtering, all the original data repopulates the grid?
Hopefully I'll figure it out before someone posts back. Also, as a side note, would it be possible to include comments in the search script fot this site?
Lots of times I've read something in the comments, but can't remeber which post it was in so I've tried searching but that seems to only search the main post.
Thanks.
<cfformitem type="script">
#include "path/file.as" (note, no ';' required.)
</cfformitem>
as suggested above. But my flash form will not load. Is there something i may be missing?
One - paste the contents of your include where the include is and try to load that - you should get an error message if there is a prob with it.
Two - are you inside of a cfoutput? If so, escape your # -
##include....blah
Change the last else from:
grid.dataProvider = [];
to:
if(_global.unfilteredData[grid.id] != undefined) grid.dataProvider = _global.unfilteredData[grid.id];
I did the two things you suggested. It is not located in a cfoutput tag. And when I paste the code from the as file to the cfform, the form loads. Can you have the onload function for a cfform in the as file?
I'm also trying to populate a grid via remoting and then apply a filter to the grid data. How did you get this to work? My remoting work and the filter worked before I set up the remoting. I'm trying to call the filter function from the onResult function but I can't get it to work. Can you post your code where you call the function and display the results?
Thanks!
Please ignore my previous post. I figured it out. I had the right code in the wrong order!
I'm struggling with calling a function from within a function. Basically, I insert some data into a database via remoting. On the result of that call, I then re-populate a grid so that the newly inserted data shows in that grid. I also need to refresh other grids in the form with the new data and so I have tried to call a function on that same result.
I have tried setting the scope i.e.
var getData = getData
but still no luck.
I noticed that the 'Load it with remoting' does the same thing i.e. calls the getData() function from within the onFormLoad() function, but I can't apply it to return calls from remoting.
Any ideas?!!!!!
Thanks.
I've been successful with:
myGrid.dataProvider = results.items;
var getData:Function = getData;
getData();
Not sure if this will work in every scenario but it works where I need it to.
Thanks for your reply. I tried your code but it still doesn't work!
Which scenarios have you found that this does and doesn't work?
Could you possibly post your code where you use this... maybe I can rework what I've got to fit more in line with yours.
Thanks for your help.
<cfset myQ = queryNew("col1,col2,checkCol")>
<cfloop from="1" to="8" index="x">
<cfset dummy = queryAddRow(myQ, 1)>
<cfset dummy = querySetCell (myQ, "col1", x)>
<cfset dummy = querySetCell (myQ, "col2", x*10)>
<cfif (x mod 2) is 0>
<cfset dummy = querySetCell (myQ, "checkCol", "Y")>
<cfelse>
<cfset dummy = querySetCell (myQ, "checkCol", "N")>
</cfif>
</cfloop>
<cfoutput>
<cfform name= "foo" format="Flash" action="test.cfm" timeout="1800"
method="post" skin="haloSilver" width="625" height="425" onload="formOnLoad()">
<cfformitem type="script">
function formOnLoad(){
// Color Rows as applicable based upon any issues found
// Based on code found on http://www.asfusion.com/blog/
var listener:Object = {};
var myColor:Number = 0xB0C4DE;
var i:Number = 0;
var unattached:mx.controls.DataGrid = unattached;
listener.modelChanged = function(evt):Void {
<!--- remove listener, so that we are not longer notified of model changes --->
unattached.removeEventListener('modelChanged',listener);
<!--- Highlight items --->
//make the loop with onEnterFrame instead of a "for"
_root.onEnterFrame = function (){
if(i < unattached.length) {
//do one iteration of the loop
if (unattached.getItemAt(i).checkCol == 'Y'){
_root.updateColor(i,myColor);
}
i++;
}
else {
//end the loop
_root.onEnterFrame = undefined;
}
}
//this is the function that does whatever we need in each iteration
_root.updateColor = function (index,colorValue){
//change the color of the edited row
unattached.setPropertiesAt(index, {backgroundColor:colorValue});
};
}
unattached.addEventListener('modelChanged',listener);
};
</cfformitem>
<!--- Display Grid --->
<cfgrid name="unattached" format="Flash" rowheaders="no" query="myQ" sort="yes" selectMode="edit" selectColor="##D2B48C">
<cfgridcolumn width="100" name="col1" header="One" select="yes">
<cfgridcolumn width="100" name="col2" header="Two" select="no">
<cfgridcolumn width="100" name="checkCol" header="Y/N" select="no">
</cfgrid>
</cfform>
</cfoutput>
I don't think you can select multiple items in a cfgrid.
Your problem was a little more complex. But I have a solution. It was not that only the visible rows were updated but that the onEnterFrame was killed by some other component at a point so it couldn't finish the loop. What you will need to do is to put the onEnterFrame somewhere other than the root, in an empty movieclip:
<!--- Highlight items --->
//make the loop with onEnterFrame instead of a "for"
var mcX = _root.createEmptyMovieClip("mcX",1000);
mcX.i = 0;
mcX.onEnterFrame = function (){
if(i < unattached.length) {
//do one iteration of the loop
if (unattached.getItemAt(i).checkCol == 'Y'){
_root.updateColor(i,myColor);
}
i++;
}
else {
//end the loop
mcX.onEnterFrame = undefined;
}
}
You can put the function in scope like todd showed you, it has to be *before* you declare the remoting function (onResult), just like we do for the controls (look at the post example code).
There is a problem, however, if that function calls another one (it will never get called). So, in order to avoid all that, just call it with _root. In the post example it would be _root.getData(). I don't know if this is very elegant, but that's what I've been using to avoid problems when calling functions that call other functions.
Thanks for your help once again. At this stage elegance doesn't concern me, just as long as it works!!
Thanks.
This one is driving me nuts. I have a cfform that I am pulling data into by invoking a CFC on the CFM page. I want the form to have styles applied to certain elements using the onload function and myFormElement.setStyle(yada, yada);. Now here is where I am newbie city. To translate CF recordset vars into actionscript I am taking a "non"-visible cfinput=text field and pulling #myRS.data# into that field and calling the value into actionscript (myText.text). The problem is, the value is not there during the onload function as you well know. I know there is a better way to do this. Help. :)
Thanks!
I don't think there is any easy way to know when the text input is populated...
You could use one hidden input like this
<cfinput type="hidden" bind="{(loadChecker.text.length>0)?alert('arrived'):'1'}" name="loadCheckerTrigger">
<cfinput type="Text" value="some value" name="loadChecker">
that checks when a regular input's value has been updated and then trigger a function that does what you need instead of the alert.
When trying to run your code I received the following message: Attribute validation error for tag CFFORMITEM. The value of the attribute TYPE, which is currently "script", must be one of the values: HRULE,HTML,TEXT,VRULE,SPACER
Are there some settings that need to be changed on the server? Windows 2000, CFMX7 JRun.
Thanks
<cfquery name="gettechnicians" datasource="#request.dsn#">
select TechID,FirstName,LastName from technicians
</cfquery>
<cfparam name="url.something" default="Sean">
<cfform name="TechnicianTool" onload="onFormLoad()" format="flash" width="500" height="400">
<cfformitem type="script">
function onFormLoad(){
var listener:Object = {};
//put the controls in scope to avoid calling _root
var contactList:mx.controls.DataGrid = contactList;
listener.modelChanged = function(evt):Void {
alert('Data loaded... select first item');
contactList.removeEventListener('modelChanged',listener);
_root.applyFilter(term.text,contactList,['TechID','FirstName','LastName']);
}
listener.applyFilter = applyFilter;
contactList.addEventListener('modelChanged',listener);
}
function applyFilter( term:String, grid:mx.controls.DataGrid, columns:Array ):Void {
var filterTerm:String = term.toString().toLowerCase();
if(filterTerm.length > 0) {
if(_global.unfilteredData[grid.id] == undefined){
if (_global.unfilteredData == undefined){
_global.unfilteredData = {};
}
_global.unfilteredData[grid.id] = grid.dataProvider.slice(0);
}
var filteredData:Array = [];
for(var i = 0; i< _global.unfilteredData[grid.id].length; i++) {
var item:Object = _global.unfilteredData[grid.id][i];
var added:Boolean = false;
for(var j = 0; j< columns.length; j++){
if(!added){
var value:String = item[columns[j]].toString().toLowerCase();
if(value.indexOf(filterTerm) != -1) {
filteredData.push(item);
added = true;
}
}
else {
break;
}
}
}
grid.dataProvider = filteredData;
}
else {
if(_global.unfilteredData[grid.id] != undefined) grid.dataProvider = _global.unfilteredData[grid.id];
}
}
</cfformitem>
<cfformgroup type="panel" label="Search Technicians">
<cfformgroup type="horizontal">
<cfinput type="text" name="term" width="120" value="#url.something#" onchange="applyFilter(term.text,contactList,['TechID','FirstName','LastName'])" label="Filter by:">
</cfformgroup>
<cfgrid name= "contactList" query="gettechnicians" height="200" rowheaders="false">
<cfgridcolumn name="TechID" header="TechID">
<cfgridcolumn name="FirstName" header="First Name">
<cfgridcolumn name="LastName" header="Last Name">
</cfgrid>
</cfformgroup>
<cfformgroup type="tabnavigator">
<cfformgroup type="page" label="Add / Edit Properties">
<cfformgroup type="horizontal" label="Your Name">
<cfinput type="text" required="Yes" name="firstName" label="First" value="" width="100"/>
<cfinput type="text" required="Yes" name="lastName" label="Last" value="" width="100"/>
</cfformgroup>
</cfformgroup>
<cfformgroup type="page" label="Add / Edit Stuff">
<cfformgroup type="horizontal" label="Your Address">
<cfinput type="text" required="Yes" name="address" label="Address" value="" width="100"/>
<cfinput type="text" required="Yes" name="city" label="City" value="" width="100"/>
</cfformgroup>
</cfformgroup>
</cfformgroup>
</cfform>
I've been working with the exact code (the date formatter) you've listed above literally all day. I've tried every permutation of the syntax to no avail. I tried your recommendation to include the code (which I wrapped in a simple function) in an external 'as' file. It worked perfectly. It is beyond me why functions as elementary as getDate(), getMonth(), etc. are non-usable in a CFForm, but the workaround seems to have done the trick. Has anyone uncovered any drawbacks or latent flaws with using this method?
On another note, are there any good references available for Flash Form development using CFForm? I'm getting tired of searching the entire internet everytime I hit a speed bump (although this site has been a goldmine of information).
Thank You
You may want to check out http://cfsilence.com.
Someone needs to cull all this information and write a book. I've always been a huge fan of one stop shopping.
But I'm wondering if this will even help me...
Because my query results are so big 20K records, the grid takes a long time to load.
Would "Run the filter function" help with this. It sounds like the data still loads it just doesn't show until the selection is made?
<cfformitem type="script">
function onFormLoad()
{ data.selectedIndex = 0; }
</cfformitem>
BUT now my onChange function on the grid does not work.
<cfgrid name="data" query="getArtists" height="160" width="510" rowheaders="false" onchange="{vensite.selectedIndex=0}{vendiv.selectedIndex=0}{status.selectedIndex=0}
for(var i:Number = 0; i<vensite.length; i++)
{if(vensite.getItemAt([i]).data==data.selectedItem.vsite)vensite.selectedIndex=i}
for(var i:Number = 0; i<vendiv.length; i++)
{if(vendiv.getItemAt([i]).data==data.selectedItem.vdivision)vendiv.selectedIndex=i}
for(var i:Number = 0; i<status.length; i++)
{if(status.getItemAt([i]).data==data.selectedItem.Status)status.selectedIndex=i}">
I tried to move this code to the onload function but that did nothing to set the selection fields onload or onChange.
These fields are sometimes null. Any help would really be appreciated.
I was using the following binding statement on most of my cfinput tags on a app using flash remoting. Works fine.
bind="{(mygrid.selectedItem!=undefined)?mygrid.selectedItem.field1:''}"
Since I kept getting "null" responses in fields that had not been completed, I changed to this:
bind="{(mygrid.selectedItem.length!=null)?mygrid.selectedItem.field1:''}"
This worked great for a few cfinputs. When I changed ALL cfinputs to match I threw the 32K error.
So I stripped out TONS of extra action script code to see how far off I was but I still threw the error! I took out way more than was added.
I am wondering why this happened. The only conclusion I can draw is that the 32K error does not just relate to the size (number of lines) of the app but also to the types of evaluations used. Thoughts?
Way back when (third comment from the top) you wanted to pass a variable to contactList.selectedIndex = #your variable#
You mentioned later that you got it working. What was your solution as I'm trying to do the exact same thing.
Daniel
post your code and i'll see if i can help.
don't forget to beware of the recompile though -
But just the act of writing it down clarified my thinking. I didn't declare it as a variable within the script. I have it working well now with a session variable. BTW -- thanks for the heads up on vPosition as well
Daniel
function onFormLoad(){
var listener:Object = {};
//put the controls in scope to avoid calling _root
var getData:Function = getData;
var search:Function = search;
var patientGrid:mx.controls.DataGrid = patientGrid;
listener.modelChanged = function(evt):Void
{
//alert('Data loaded... clear datagrid until department is selected');
patientGrid.removeEventListener('modelChanged',listener);
getData();
search('',contactList,[]);
}
listener.search = search;
patientGrid.addEventListener('modelChanged',listener);
}
function getData():Void
{
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection( "http://chextdev.tch.harvard.edu/flashservices/gateway/");
var myService:mx.remoting.NetServiceProxy;
var responseHandler:Object = {};
var patientGrid:mx.controls.DataGrid = patientGrid;
responseHandler.onResult = function( results: Object ):Void
{
patientGrid.dataProvider = results.items;
mx.managers.CursorManager.removeBusyCursor();
}
responseHandler.onStatus = function( stat: Object ):Void
{
alert("Error while calling cfc:" + stat.description);
mx.managers.CursorManager.removeBusyCursor();
}
myService = connection.getService("ppoc.patientGrid", responseHandler );
mx.managers.CursorManager.setBusyCursor();
myService.getDataSet();
}
private function editPatient():Void
{
getURL("editPatient.cfm?pat_id=" + patientGrid.selectedItem.PAT_ID);
}
private function newPatient():Void
{
getURL("addPatient.cfm")