Oct
05

Knowing when the cfform data arrives

111 comments Posted by: Laura

So 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>

Live example 1

Live example 2

Live example 3

Download the source

Category: CFForm | ColdFusion |

111 Comments so far

Write yours
Michael White
Incredible stuff... you have a great understanding of how to apply that actionscript stuff... But how does one learn actionscript as it applied to coldfusion flash forms? any actionscript 2.0 book I've picked up so far has examples that use &quot;forbidden&quot; keywords. Do I just need an actionscript 1.0 book?
Neil Bailey
2. Neil Bailey wrote on October 06, 2005 at 7:02 AM
That is an EXCELLENT question....
Todd
3. Todd wrote on October 06, 2005 at 10:12 AM
Wonder why this doesn't work:

<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;
William
Todd,

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 = &lt;cfoutput&gt;#url.indexnum#&lt;/cfoutput&gt;;

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.
todd
5. todd wrote on October 06, 2005 at 12:01 PM
William - I figured it out - it was a complete ID10T error - The code works now but I get a weird problem - the grid is BLANK!! If i scroll up it reappears, but onload it's blank.
Todd
6. Todd wrote on October 06, 2005 at 4:51 PM
Update: My grid isn't blank anymore and the code works great. Don't know if anyone noticed a little gem in my code:

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.


disidiosus
7. disidiosus wrote on October 07, 2005 at 1:38 AM
Thanks for giving the modelChanged some press, it's a handy event. It also lead me to some much needed and very helpfull actionscript code in the Flex documentation. Guess I'd just never got that far before.

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!
BM
Hae you ever encountered two cfforms loading on top of one another? They are the same form but two instances load.

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 &lt;cfpop&gt; ...
Laura
disidiosus,
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.
Ville
The code under "Selecting the first item" saved my day. Thank you!! :)
Asher Gilbert
William,

Could you clarify what you mean by...

&quot;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...&quot;

And maybe give an example of how to better use CF variables in actionscript to avoid this issue.

Thanks
Laura
Asher,
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)
Asher Gilbert
Laura,

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
todd
14. todd wrote on October 13, 2005 at 5:27 AM
Asher:

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. &lt;cfinput type=&quot;text&quot; name=&quot;#url.variable#&quot;&gt;

Not in the actionscript - which would be like this:

&lt;cfinput type=&quot;text&quot; name=&quot;textbox1&quot; onchange=&quot;var test = '#url.variable#'; if (test == &quot;testing&quot;){alert('test');}&quot;
Laura
Asher and Todd,
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 &quot;value&quot; 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 &lt;cfif&gt; 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.
todd
16. todd wrote on October 13, 2005 at 11:11 AM
Laura:

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, &amp; 5 - cols 4, 6, &amp; 7 are fine.

Any ideas???
Anthony
17. Anthony wrote on October 13, 2005 at 12:13 PM
I'm trying to take this a bit further and having a problem. I've got data loading and everything fine. (great work on all the examples!) But what i'm having problems with is making items visible once a row is selected. I have a button who's label is bound to the selected cell and can make it visable. The problem is I have a cfformgroup type=panel that I want to make visable too. But it doesnt seam like you can give it a name. How can i target a panel from an AS function? I tried binding the visible property to selectedItem but couldn't get that to work.
todd
18. todd wrote on October 13, 2005 at 3:08 PM
Anthony - check out the mxna reader post in this blog - that should give you some ideas on how to dynamically hide the panel.
Neil Bailey
19. Neil Bailey wrote on October 13, 2005 at 5:23 PM
Anthony,

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.
Jason
20. Jason wrote on October 13, 2005 at 5:41 PM
my session in the component was not defined when it is remoting.
Is there any way that I can get my session?
Jason
21. Jason wrote on October 13, 2005 at 7:43 PM
Too sleepy i guess, CFC variable solved the problem. Sorry for the dumb question, got 2 more questions :p

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().
WayneG
22. WayneG wrote on October 13, 2005 at 10:12 PM
Dear Laura

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
disidiosus
23. disidiosus wrote on October 14, 2005 at 7:37 AM
Reserved Words work around.

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()+&quot;/&quot;+(myDate.getMonth()+1)+&quot;/&quot;+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.
Garry
Just an aside from an old (51) Cold Fusion Programmer who started with 1.5 in Germany. I had a problem with the 32k limit yesterday and, not being a flash programmer, almost turned the project out the door. Then I started playing with two scripts I found here and VIOLA!!! the 32K limit is no longer a problem.

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.
disidiosus
25. disidiosus wrote on October 14, 2005 at 8:39 AM
Reserved words workaround.

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.
elfrick
26. elfrick wrote on October 18, 2005 at 4:09 AM
Quick Q:

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???




disidiosus
27. disidiosus wrote on October 19, 2005 at 1:49 AM
To include a .as file:

&lt;cfformitem type=&quot;script&quot;&gt;
#include &quot;path/file.as&quot; (note, no ';' required.)
&lt;/cfformitem&gt;
WayneG
28. WayneG wrote on October 19, 2005 at 10:15 PM
Pls help...

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
Michele
29. Michele wrote on October 21, 2005 at 1:49 PM
Has anyone figured out how to modify the first example for a cfselect? I would like to select the first option in my cfselect on form load, which will then trigger the grid to filter. Seems simple, but I can't get it to work. Thanks for any ideas.
Laura
Michele,
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.
Michele
31. Michele wrote on October 21, 2005 at 11:46 PM
Thank you for the speedy reply, Laura. To be a bit more specific... I am trying to modify the example so that on load my grid is filtered based on an option in a cfselect (specifically to show active records, as opposed to inactive or all records). The confusing part (for me) is that my filter is saved in a cfsavecontent tag, not a function. So can I call that from within the onFormLoad function? Or do I need to convert my cfsavecontent tag to a function? Not that I know how to do that :-) I'm using the cfsavecontent because I was able to figure out how to modify it to first filter based on cfselect and then search in specific column - I just combined two of your examples. I could not figure out how to do this with the filter function. Here's my cfsavecontent:

<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.
Jason
32. Jason wrote on October 23, 2005 at 3:34 PM
Laura,
How can I select the first item AFTER it done loading with remoting?
Thanks
Wayne G
33. Wayne G wrote on October 24, 2005 at 12:52 AM
Laura,

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
Fritz Dimmel
Hi!
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 &quot;dgFilter()&quot;. 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
WayneG
35. WayneG wrote on November 02, 2005 at 10:51 PM
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 &quot;ColdFusion Flash Forms Macromedia Developer Center article&quot; 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..

Marco
36. Marco wrote on November 04, 2005 at 3:00 AM
Hi,

the filter casting a &quot;string&quot;, but it's mixed 1 with 13. How apply a exact, numeric filter?

Thanks,
Marco
Marco
37. Marco wrote on November 04, 2005 at 7:33 AM
I have resolved in this mode:

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 &quot;edit&quot;, no array returned on the form submit.

Help me!

Marco
Laura
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.
Neil Huyton
Hi.

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.
todd
40. todd wrote on November 06, 2005 at 3:17 PM
Neil:

Post your filtering code - it's probably something simple. Are you using toLowerCase()? Sometimes I forget to do that.

Todd
Laura
Neil,
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.
Neil Huyton
42. Neil Huyton wrote on November 07, 2005 at 3:02 AM
Todd, Laura... thanks for your help.

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!
Neil Huyton
43. Neil Huyton wrote on November 07, 2005 at 3:12 AM
Okay... so now I'm just being picky!
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.
Melissa
44. Melissa wrote on November 09, 2005 at 1:45 PM
I have tried using
<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?
todd
45. todd wrote on November 09, 2005 at 1:59 PM
Try two things Melissa.

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
Laura
Neil,
Change the last else from:
grid.dataProvider = [];

to:
if(_global.unfilteredData[grid.id] != undefined) grid.dataProvider = _global.unfilteredData[grid.id];
Melissa
47. Melissa wrote on November 09, 2005 at 2:32 PM
Todd,

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?
todd
48. todd wrote on November 09, 2005 at 7:39 PM
Are you sure you have the path correct?
Michele
49. Michele wrote on November 13, 2005 at 1:46 PM
Neil,

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!
Michele
50. Michele wrote on November 13, 2005 at 1:51 PM
Neil,

Please ignore my previous post. I figured it out. I had the right code in the wrong order!
Neil Huyton
51. Neil Huyton wrote on November 16, 2005 at 4:30 AM
Hi.

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.
todd
52. todd wrote on November 16, 2005 at 5:04 AM
Neil:

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.
Neil Huyton
53. Neil Huyton wrote on November 16, 2005 at 6:46 AM
Hi Todd.

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.
Adam
54. Adam wrote on November 16, 2005 at 9:31 AM
I'm trying to highlight rows based upon data values when the grid loads, but am having little luck. It seems as though the rows which are initally displayed by the grid format fine, but not those below. Any ideas?

<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>
Neil Huyton
55. Neil Huyton wrote on November 16, 2005 at 10:53 AM
Hi Adam.

I don't think you can select multiple items in a cfgrid.
Neil Huyton
56. Neil Huyton wrote on November 16, 2005 at 10:56 AM
Sorry Adam.. just looked at your example again, you can select multiples....doh!!!
Laura
Adam,
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;
   }
}
Laura
Neil,
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.
Neil Huyton
59. Neil Huyton wrote on November 17, 2005 at 4:38 AM
Hi Laura.

Thanks for your help once again. At this stage elegance doesn't concern me, just as long as it works!!

Thanks.
Adam
60. Adam wrote on November 17, 2005 at 4:40 AM
Laura, thanks. That was a huge help to a project I'm working on. You rock!
Joshua Buttler
Hi guys,
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 &quot;non&quot;-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!
Laura
Joshua,
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.
Mike Kaminsky (ICF Consulting)
63. Mike Kaminsky (ICF Consulting) wrote on December 22, 2005 at 3:02 PM
I believe the reason why the cftree does not respond to the &quot;modelChanged&quot; event is because the cftree uses a different dataProvider than the one associated with the cfgrid and cfselect. The cftree dataProvider is based on XML and does not broadcast similar events.

Maya
64. Maya wrote on December 30, 2005 at 10:45 AM
Your cfgrid-onload-selectitem.cfm code is exactly what needed but I can not make it work.
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 &quot;script&quot;, 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





todd
maya - you need to run the cfmx 7.0.1 updater. cfformitem type=script was not introduced until then.
Sean
66. Sean wrote on January 03, 2006 at 4:27 AM
Thanks a lot for the tips, they're truly great, I feel slightly ahead of this slow moving product. BUT.. I'm having so much trouble getting an url variable into my flash form... I've included my code, works great, except I need it to auto-filter based on an url variable as well (I'm migrating from an old system), I figured I'd just use the data onload listener to simply rerun the filter function after the grid was loaded.. this looks fine, but it does not recognize the term.text variable that I have passed it, presumably because it hasnt arrived yet, it's driving me nuts... any ideas how I can get an url variable into the code without having to recompile the as everytime?


<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>
Michael
Disidious,

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
todd
Michael,

You may want to check out http://cfsilence.com.

Michael
Wow...Another great site. Thanks for the tip, Todd.

Someone needs to cull all this information and write a book. I've always been a huge fan of one stop shopping.
Michael White
you guys do know about Ray Camden's new site: http://www.coldfusioncookbook.com/
Thomary
71. Thomary wrote on January 13, 2006 at 1:19 PM
I have to wait for the 7.0.1 updater to be installed. I can not use the type=&quot;script&quot;.

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 &quot;Run the filter function&quot; help with this. It sounds like the data still loads it just doesn't show until the selection is made?
Thomary
72. Thomary wrote on February 13, 2006 at 7:30 AM
We added an onload function, which will select the first line in the grid.
<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.
Joe Rebis
Regarding the 32K issue (didn't know wehere else to place this comment) I had something interesting come up.

I was using the following binding statement on most of my cfinput tags on a app using flash remoting. Works fine.

bind=&quot;{(mygrid.selectedItem!=undefined)?mygrid.selectedItem.field1:''}&quot;

Since I kept getting &quot;null&quot; responses in fields that had not been completed, I changed to this:

bind=&quot;{(mygrid.selectedItem.length!=null)?mygrid.selectedItem.field1:''}&quot;

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?
Daniel
74. Daniel wrote on March 14, 2006 at 8:46 AM
Todd,
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
todd
i'm not positive, but i think i failed to pass the var i was expecting in the url. make sure your passing the var in (a cfparam never hurts) and make sure you're within a cfoutput.

post your code and i'll see if i can help.

don't forget to beware of the recompile though -
Daniel
76. Daniel wrote on March 14, 2006 at 9:55 AM
Thanks Todd,
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
Andy
77. Andy wrote on April 06, 2006 at 7:36 AM
I am trying to filter a grid that is loaded by remoting. The grid loads, but when I start typing in the text field to filter the grid, nothing happens, but when you backspace out, the entire grid disappears. It reappears after you hit the space bar once. Below is my code... This is confusing...

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")