Our Blog

Editable Grid
Some time ago I made a post where I showed how to filter a cfgrid by typing in a input field. I received a lot of comments requesting to do the same but using an editable cfgrid. The result in this code:

<cfsavecontent variable="actionInsert">
   GridData.insertRow(myGrid);
   _global.backupDP.push(myGrid.getItemAt(myGrid.length -1));
</cfsavecontent>
<cfsavecontent variable="actionDelete">
   var item = myGrid.selectedItem;
   if(_global.backupDP != undefined)
   {
      for(var i = 0; i < _global.backupDP.length; i++)
      {
         if(_global.backupDP[i] == item)
         {
            _global.backupDP.removeItemAt(i);
         }
      }
   }
   GridData.deleteRow(myGrid);
</cfsavecontent>
<cfsavecontent variable="actionFilter">
if(_global.backupDP == undefined)
   {
       _global.backupDP = myGrid.dataProvider.slice(0);
   }
   var backupDP = _global.backupDP;
   var fortext = forInput.text.toLowerCase();
   var selected = column.selectedItem.data;
   myGrid.dataProvider.removeAll();
   
   for(var i =0; i < backupDP.length;i++)
   {
      var item = backupDP[i];
      if(item[selected].toString().substr(0,fortext.length).toLowerCase() == fortext)
      {
         myGrid.dataProvider.addItem(item);
      }
   }
</cfsavecontent>
<cfform name="myForm" format="flash" width="400" height="370">
   <cfformgroup type="panel" label="Search our Members">
      <cfformgroup type="horizontal">
         <cfinput type="text" name="forInput" width="120" onchange="#actionFilter#" label="Filter by:">
            <cfselect name="column" label="in:" onchange="forInput.text=''" width="90">
               <option value="name">Name</option>
               <option value="gender">Gender</option>               
               <option value="age">Age</option>
            </cfselect>
      </cfformgroup>
      <cfgrid name= "myGrid" query="memberList" height="200" selectmode="edit" >
               <cfgridcolumn name="name" header="Name">
               <cfgridcolumn name="gender" header="Gender">
               <cfgridcolumn name="age" header="Age">
            </cfgrid>
   </cfformgroup>
   <cfformgroup type="horizontal">
      <cfinput type="submit" name="submit" value="Submit"/>
      <cfinput type="button" name="inser" value="Insert" onclick="#actionInsert#"/>
      <cfinput type="button" name="remove" value="Delete" onclick="#actionDelete# "/>
   </cfformgroup>
</cfform>

Live Example
Download the source

Related Posts
Filtering a grid as you type in a cfform
Filtering a list as you type in a ColFusion Flash Form

Nahuel Foronda

Nahuel Foronda

56 Comments

  1. Steven Ross
    this line fails when there are spaces in items in your grid (also on a number):

    if(item[selected].substr(0,fortext.length).toLowerCase() == fortext)

    if you replace it with this it works:

    if(_global.arrMembers == undefined) _global.arrMembers = FileGrid.dataProvider.slice(0);
        var arrMembers = _global.arrMembers;
        var arrDisplay:Array = [];
        var fortext = forInput.text;
        var selected = column.selectedItem.data;
       
        for(var i = 0; i &lt; arrMembers.length; i++)
        {
          
           if(selected == 'NumberColumn')
           {
              if(arrMembers[i][selected].toString().indexOf(fortext) != -1)
              {
                 arrDisplay.push(arrMembers[i]);
              }
           }
           else{
          
              if(arrMembers[i][selected].toLowerCase().indexOf(fortext.toLowerCase()) != -1)
              {
                 arrDisplay.push(arrMembers[i]);
              }
           }
          
        }
        FileGrid.dataProvider = arrDisplay;

  2. Felipe

    Felipe

    How do I do to make it search in every part of the filed, not only in the first letter? As you did in the other post?
  3. Steven Ross
    change this line:

    if(item[selected].substr(0,fortext.length).toLowerCase() == fortext)

    to:

    if(arrMembers[i][selected].toLowerCase().indexOf(fortext) != -1)
  4. John Farrar

    John Farrar

    I also found this works to resolve issues with numbers. Just run the table through a Query of Queries...

    CAST([year] AS VARCHAR) as years

    That fixed the issue I was having and should work all around if you need the functionality.
  5. How do you validate data in cfgrid, ie. dates, expressions etc.
  6. Troy Montour
    I'm using the filter grid so a person can search for a customer.
    now I need to pass back what customer they clicked on so I can pass this back to the Database to find this customers Orders.

    Is there a way to do this?
  7. Michael White
    I would like to maintain the Flash Form look and feel throughout my ColdFusion Application and give users some cool features too. I would like to use CFGRID to allow a user to preview report data (say a list of orders) and either Export the list to excel/plain text or jump the the record details edit page (if they have rights). to make a long story short, what's the easiest way to link to another form from a data grid?
  8. mafdoc
    Steve Ross - I am trying to filter on a number column. I used your code and it did work but it filtered on every column of my grid not just the selected &quot;in&quot; column. Would you let me know how to filter only on the &quot;in&quot; column.
    I tried to adjust your code with the original code but when I enter a number to be filtered all my data disappears. Although, I can still filter on the other columns (which are listed in the &quot;in&quot; select list) The adjusted code:

    &lt;cfsavecontent variable=&quot;actionFilter&quot;&gt;
       if(_global.arrMembers == undefined) _global.arrMembers = data.dataProvider.slice(0);
       var arrMembers = _global.arrMembers;
       var arrDisplay:Array = [];
       var fortext = forInput.text.toLowerCase();
       var selected = column.selectedItem.data;
       
       for(var i = 0; i &lt; arrMembers.length; i++)
    {
    if(selected == 'NumberColumn')
    {
    if(arrMembers[i][selected].toString().indexOf(fortext)!=-1)
       {arrDisplay.push(arrMembers[i]);
    }
    }
       else
       
    {
    if(arrMembers[i][selected].substr(0,fortext.length).toLowerCase() == fortext)
    {
    arrDisplay.push(arrMembers[i]);
    }
    }
    }
       data.dataProvider = arrDisplay;
    &lt;/cfsavecontent&gt;

    I'll keep trying but I would appreciate any help.
  9. mafdoc
    I got the answer from Laura on the original posting of Filter as you type http://www.asfusion.com/blog/entry/filtering-a-list-as-you-type-cfform-flash.
    added .toString() between the ...[selected] and .substr...
    Thanks so much.
  10. Gary Rennilson

    Gary Rennilson

    I am new to this and trying to get this filtering to work. I applied this code to my existing grid using my SQL data. The actionInsert and actionDelete works as provided, but when I try and apply any filter it removes all entries in the grid. Should this be filtering off the local data in the grid or does it need to be bound to my database somehow?
  11. Laura
    Gary,
    perhaps you have the same problem described by mafdoc (when data contained numeric fields). I updated the source to contain the change.
    Otherwise it should work as is.
  12. Michael White
    Flash forms are case sensitive so if you type a form control name in lower case and the actual control name is in mixed case it won't work
  13. Gary Rennilson

    Gary Rennilson

    Laura, using the added .toString() worked! Thanks so much.
  14. John
    I wanted to ask you a quick question. I thought in a post which I can’t find right now someone said that can get more data when you switch tabs.

    I am talking about using tab navigator in cfform with format flash.

    Lets say what show up in tab2 depends on what you select in tab 1.

    So I need to refesh what tab2 is showing when someone click on tab2 based on what record the user choose in tab1.

    Is this possible?

    Basicaly whenever someone clicks on tab2 I want to refresh the cfgrid with new data without refreshing the entire page.


    What I wish I could do is put a cfquery inside of the second cfformgroup (the one named tab2). Have that run each time some one click on tab 2.


    The other thing I have recently heard about about is CF.Query() function.

    Can I do this on tab change inside of my coldfusion file. If so can you send me an example of how to do this.

    If I don't hear from you I am going to use this filtering code to get all the data when the page first loads and then filter what I show based on what was chosen in tab1. The problem with this is that as amont of data get huge this will become impossible.

    Thanks for any help you can give me.

    John
  15. John,
    You have different options. You can do that with remoting and ask for a small amount of data each time like in this example:
    http://www.asfusion.com/blog/entry/populating-a-cfgrid-with-flash-remoting

    Or you can download everything to the client like in this example:
    http://www.asfusion.com/blog/entry/quick-grid-bindings
  16. John
    I have 3 questions about how to controlthe tabs.
    1. Is there any event that get triggered when a new tab is selected.

    2. Can I change the tab selected manually.

    3. Is there a way to hide or disable certain tabs depending on choices the user make outside of the tabnavigator.

    Thanks in advance

    Kourosh
  17. John
    1. onchange
    2. myTab.selectedIndex = 0; // 1,2,3,4
    3. try with bindings, or use the visible property
  18. John
    Thanks Nahuel.

    I ended up having to use enabled = false
    for hiding the tabs.

    the visible property doesn't do anything for individual tabs. Even when you hard code set at the very start it still shows it.
    Like this:
    &lt;cfformgroup label=&quot;Documents&quot; type=&quot;page&quot; visible=&quot;no&quot;&gt;



  19. mafdoc

    mafdoc

    I am currently using the filter grid with the query getArtists (shown below).
    Now I want to get more data from another datasource and table.
    I can not get query of query to work. This cfoutput shows all the data I need.
    Can someone help me put this into a cfquery so I can use that query in the filter?

    &lt;cfquery name=&quot;getArtists&quot; datasource=&quot;docpers&quot;&gt;
    SELECT UserName, FirstName, LastName, WorkPhone, Division, Status
    FROM tblmaster
    WHERE status &lt;&gt; 'I'
    ORDER BY UserName
    &lt;/cfquery&gt;

    &lt;cfoutput query=&quot;getArtists&quot;&gt;
    &lt;cfquery name=&quot;getsiteinfo&quot; datasource=&quot;Site&quot;&gt;
    SELECT *
    FROM site
    Where username = '#getArtists.UserName#'

    &lt;/cfquery&gt;
    #getArtists.UserName#, #getArtists.FirstName#, #getArtists.LastName#, #getArtists.Division#, #getsiteinfo.site#, #getsiteinfo.location#&lt;&lt;br&gt;
    &lt;/cfoutput&gt;

    Thanks for any help.
  20. mafdoc

    mafdoc

    This query throws an error
    &quot;Element USERNAME is undefined in TBLMASTER.&quot;

    &lt;cfquery name=&quot;getArtists&quot; datasource=&quot;docpers&quot;&gt;
    SELECT UserName, FirstName, LastName, WorkPhone, Division, Status
    FROM tblmaster,
    Site.site
    WHERE status &lt;&gt; 'I'
    AND username = '#tblintranetmaster.UserName#'
    ORDER BY UserName
    &lt;/cfquery&gt;

  21. Laura
    David,
    Of course there is! All the examples with cfform use the Flex engine. In fact, it should be pretty straight forward to do it, although you will need to get the data manually (either with remoting, xml, web service, etc)
  22. david
    thanks Laura, I modified the example today and got it to work using remoting like you suggested. I will try and post my actionscript tomorrow. thanks for the help :)

    David
  23. function doFilter(myFilter)
    {
    var filteredRecords = new Array();
    var filterText:String = myFilter;
       
       for(var i = 0; i &lt; RemoteObjectName.ModelName.result.length; i++ )
       {
       var curRecord = RemoteObjectName.ModelName.result[i];
          var name = RemoteObjectName.ModelName.result[i].DataGridColumnName;
                
          if(name.substring(0,filterText.length).toLowerCase() == filterText.toLowerCase())
          {
             filteredRecords.push(curRecord);

          }
       }

       DataGridName.dataProvider = filteredRecords;
    }
  24. I haven't been able to get cfgridupdate to work with anything. Since you have an editable grid with a flashremoting link, how would I use cfgridupdate with this?

    Thanks
  25. Laura
    Mike,
    I never use cfgridupdate so I can't really help you with that. The code of the post should work with cfgridupdate if you submit the form though, but I have not tested it. Flash remoting is a different animal. cfgridupdate requires a form post, and you do not post a form post when you use remoting.
  26. Brad Wood

    Brad Wood

    When I populate with flash remoting this stops working.

    Specifically this line right here:
    _global.backupDP = myGrid.dataProvider.slice(0);

    doesn't work when the dataProvider was populated with remoting.

    Why does life hate me?
    Pleas tell me there is another way around this. If I get rid of the slice(0) it copies the list over but it copies by REFERENCE not by VALUE. I can't find anywhere a source that tells me what syntax would force AS to make a backup of the dataProvider by duplicating the list in memory.
  27. Michael White
    can you show/hide tabs (an entire page of a tab navigator) based on a control outside the tab navigator... like a CFGRID. I want a tab to be invisible until a selection is made in the grid.
  28. Joseph

    Joseph

    Laura -

    This is some great stuff. I'm using this to try to put together a three-level filtering system. There are three cfgrids. Selecting an item in the first one filters the second cfgrid, selecting an item in the second cfgrid filters the third cfgrid.

    I was able to modify an 'actionFilter' and an 'actionFilter2' with little problem. Change all the appropriate cfgrid references, and use _global.backupDP2 instead of _global.backupDP.

    In addition, however, there are SO MANY items in the third cfgrid, and they don't really make sense unless you've selected something from the second cfgrid, that it really needs to be hidden until something is chosen in actionFilter2.

    My solution (I thought) was simple. Give the following propety to the cfformgroup that holds the third cfgrid.

    visible=&quot;{((_global.myShowbox)?true:false)}&quot;

    In addition, make a cfsavecontent called 'actionLoad' which loads upon onLoad which looks like this:

    _global.myShowbox = 0;

    In actionFilter, which is called when clicking on the first cfgrid, add the same line before any of the rest of the code. In actionFilter2, which is called when clicking on the second cfgrid, use this code before anything else:

    _global.myShowbox = 1;

    Theoretically, this would make a variable that would toggle the visibility of the third cfgrid and its assorted controls. It would be invisible when first loading, or when selecting something from the first cfgrid, and it would become visible when making a selection from the second cfgrid.

    It didn't work.

    Not only does it not toggle visibility states, but it also stops ActionFilter from working at all. ActionFilter now removes everything from the second cfgrid, but does not repopulate it with any data.

    What did I do wrong?

    Thank you in advance for your help. Your site is one of my favorite coldfusion sites, right after the livedocs themselves.
  29. The ScareCrow
    When I populate with flash remoting this stops working.

    Specifically this line right here:
    _global.backupDP = myGrid.dataProvider.slice(0);


    I also ran into this. You could actually get the length of the data provider, but it would not assing to the global var.

    This is how I fixed it.

    In the response handler onResult

    //create array to hold results
    var myDP:Array = [];
    //loop through result set
    for(var x=0; x &lt; results.length; x++){
    //add items to the array in the form
    column name:column value
    myDP.addItem({fld_Column1:results.getItemAt(x).fld_Column1, fld_Column2:results.getItemAt(x).fld_Column2});
    }
    //assign the array to the grid data provider.
    myGrid.dataProvider = myDP;

    The filter then works when the grid is populated by remoting

    Ken
  30. Laura
    ScareCrow,
    Actually, the simplest way to make it work with remoting is doing:
    myGrid.dataProvider = results.items;
    instead of simply:
    myGrid.dataProvider = results;

    This avoids having to loop over the data which might be slow for large sets.
    The problem is that slice() is for arrays, not recordsets and the variables &quot;results&quot; holds a recordset, not an array when the component returns a query.
  31. ramzi Chekkath

    ramzi Chekkath

    Hi,

    i like the look in function but i want one of the two

    1 - either one input box and it searches in any given colum name (with out the user changing it in a list)

    2 - or multiple input boxes each one filtering a certain colum


    i personally preffer the second option but to start with first option is fine.


    eg. second option.
    insert 1 = ra
    insert 2 = c


    so it returns to me
    c1 c2
    --- ---
    ramzi chekkath
    rasberry cherry
  32. Thomary

    Thomary

    Macromedia LiveDocs system says you can use:
    &lt;cfgridcolumn name = &quot;FirstName&quot; textColor = &quot;(CX EQ Peter ? blue : black)&quot;&gt;

    I can not get this to work. Has anyone tried this? I would like combine two grids if possible but I really need to identify which listing is vendor and which are employees. I thought this would be very useful. Thanks for all your help.

  33. candlelight

    candlelight

    Refering to David's solution to filtering with grid populated with flash remoting,

    As I am quite new to actionscript, what is
    &quot;RemoteObjectName.ModelName&quot;?

    Anyone has some great example(s) of how enable filtering with grid populated with flash remoting?

    Stucked..

    Thanks
  34. Laura
    candlelight,
    See my reply to ScareCrow 3 comments above. That's all what you need to make it work with remoting. Use the code explained at http://www.asfusion.com/blog/entry/populating-a-cfgrid-with-flash-remoting
  35. Gary
    Referring to Thomary's comment about using an expression in the textColor attribute to change the text color in a cfgridcolumn.

    ------

    I've tried this too and have been unable to get it to work. I get no errors, but I also get no output, just a blank page.

    Very frustrating ...
  36. Neill
    I have changed the filter code to that of the revisted. However, I still get an empty grid when the form arrives at the processing page. Any help greatly appreciated.
  37. Joe Gutierrez

    Joe Gutierrez

    This was an excellent article, thanks! I used it to filter the grid based on multiple input fields for an address book. Here's my function.

    // this function removes records from the grid based on the input fields
    function applyFilter():Void {
    var grid:mx.controls.DataGrid = myGrid;
    var filterTerm:Array = [];
    var columns: Array = [];
    var value:Array = [];

    // array of columns that correspond to datagrid col names
    columns[0] = 'lastname';
    columns[1] = 'firstname';
    columns[2] = 'city';
    columns[3] = 'state';
    columns[4] = 'phone';

    // array of values from input fields where to get filter terms
    filterTerm[0] = frmClient.lastname.toString().toLowerCase();
    filterTerm[1] = frmClient.firstname.toString().toLowerCase();
    filterTerm[2] = frmClient.city.toString().toLowerCase();
    filterTerm[3] = frmClient.state.toString().toLowerCase();
    filterTerm[4] = frmClient.phone.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;
           var pushit:Boolean = true;
          
          for (var x = 0; x < columns.length; x++) {
             value[x] = item[columns[x]].toString().toLowerCase();
             if (filterTerm[x] != '' && filterTerm[x] != undefined)
             {
                if (value[x].substr(0,filterTerm[x].length).toLowerCase() != filterTerm[x])
                {
                   pushit = false;
                }
             }
          }
          if ( pushit == true){
             filteredData.push(item);
              added = true;
          }
        }

    grid.dataProvider = filteredData;

    }
    else {
        if(_global.unfilteredData[grid.id] != undefined) grid.dataProvider = _global.unfilteredData[grid.id];
    }
    }
  38. Andy W.

    Andy W.

    I have a cfgrid where the filtering works. One of the columns on the grid is a check box. After the user submits the form I process the rows for which the check box was changed by looping through the array form.mygrid.rowstatus.action. This array is the proper size and the code works when I do not type anything to filter the grid. If I filter the grid and change one or more rows the array form.mygrid.rowstatus.action contains 0 elements.

    I'm wondering if it has something to do with pass by value/reference situation.

    Here is the code that I used for filtering the grid.

    function applyFilter(grid:mx.controls.DataGrid):Void{
        var arrDisplay:Array = [];
       
        var fortext = name.text.toLowerCase();
        var isApplicable:Boolean = true;
       
          
       if(_global.arrMembers == undefined) _global.arrMembers = userGrd.dataProvider.slice(0);
           var arrMembers = _global.arrMembers;
       
        for(var i = 0; i < arrMembers.length; i++){
             
             //Filter on the text
             if (fortext.length > 0){
                isApplicable = filterText(fortext,i,arrMembers[i].first_nm.toString(),arrMembers[i].last_nm.toString(),arrMembers[i].org_nm.toString(),arrMembers[i].user_nm.toString());
             }
             else{
                isApplicable = true;
             }
          
             
             
          
             if (isApplicable == true){
          
                arrDisplay.push(arrMembers[i]);
                isApplicable = true;
             }
             
          }
          
          userGrd.dataProvider = arrDisplay;
    }
       
    ///filter for text
    function filterText(fortext:String, i:Number, first:String, last:String,org:String, user:String):Boolean{
          var isApplicable:Boolean;
          
          if ((first.substr(0,fortext.length).toLowerCase() == fortext || last.substr(0,fortext.length).toLowerCase() == fortext || org.substr(0,fortext.length).toLowerCase() == fortext|| user.substr(0,fortext.length).toLowerCase() == fortext) ){
             isApplicable = true;
          }
          return isApplicable;
       }
  39. Andy W.

    Andy W.

    I have a cfgrid where the filtering works. One of the columns on the grid is a check box. After the user submits the form I process the rows for which the check box was changed by looping through the array form.mygrid.rowstatus.action. This array is the proper size and the code works when I do not type anything to filter the grid. If I filter the grid and change one or more rows the array form.mygrid.rowstatus.action contains 0 elements.

    I'm wondering if it has something to do with pass by value/reference situation.

    Here is the code that I used for filtering the grid.

    function applyFilter(grid:mx.controls.DataGrid):Void{
        var arrDisplay:Array = [];
       
        var fortext = name.text.toLowerCase();
        var isApplicable:Boolean = true;
       
          
       if(_global.arrMembers == undefined) _global.arrMembers = userGrd.dataProvider.slice(0);
           var arrMembers = _global.arrMembers;
       
        for(var i = 0; i < arrMembers.length; i++){
             
             //Filter on the text
             if (fortext.length > 0){
                isApplicable = filterText(fortext,i,arrMembers[i].first_nm.toString(),arrMembers[i].last_nm.toString(),arrMembers[i].org_nm.toString(),arrMembers[i].user_nm.toString());
             }
             else{
                isApplicable = true;
             }
          
             
             
          
             if (isApplicable == true){
          
                arrDisplay.push(arrMembers[i]);
                isApplicable = true;
             }
             
          }
          
          userGrd.dataProvider = arrDisplay;
    }
       
    ///filter for text
    function filterText(fortext:String, i:Number, first:String, last:String,org:String, user:String):Boolean{
          var isApplicable:Boolean;
          
          if ((first.substr(0,fortext.length).toLowerCase() == fortext || last.substr(0,fortext.length).toLowerCase() == fortext || org.substr(0,fortext.length).toLowerCase() == fortext|| user.substr(0,fortext.length).toLowerCase() == fortext) ){
             isApplicable = true;
          }
          return isApplicable;
       }
  40. Mark Cadle

    Mark Cadle

    I will post this in the other sections as well involving filtering a grid. If you are not using remoting and do not have an editable grid so to speak, if you run a cfgridupdate it will fail saying that it can not find the grid named XXXX.

    This is only once you have filtered the grid. If you do not filter the grid then it will work. So at what point does this rename the grid? How can you keep the same grid name?

    I update the grid via a cfinput that is bound to the selectedIndex of the grid and then have a button with onclick to:
    gridname.dataProvider.editField(gridname.selectedIndex, 'COLUMN', textname.text);

    This works great and the cfgridupdate works great even when you filter the grid, but once you filter the grid, you can not run the cfgridupdate.

    I hope this makes sense.
  41. Joel Watson
    I am desperately trying to enable a filter between two grids AND being able to insert, update and delete records when a filter is applied.

    Currently, I can insert, update and delete when no filter is applied no problem (not an ideal solution), but when I try to filter, the functionality disappears and the submission sends a blank entry.

    Any ideas on this? I have read through the comments here and I cannot find anything that solves my dilemma. I really appreciate the help!

    Joel
  42. Ryan - Smurf
    This is a more efficient and much quicker way of filtering while you type. You can basically use the old school remoting tactics. Well here goes….

    file: filter.cfm

    <cfsilent>
    <cfsavecontent variable="onLoad">
       _global.loaded = true;
       <cfoutput>
          <!---create connection--->
          var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection("http://#cgi.HTTP_HOST#/flashservices/gateway");
          <!---declare service--->
          var netService:mx.remoting.NetServiceProxy;
          <!---declare component--->
          var epmComp = "xEPM.authenticated.components.empCFC";
       </cfoutput>

       <!--- includes actionscript file for form --->
       #include "actionscript/as_dataManagement.as"
    </cfsavecontent>
    </cfsilent>


    <cfform format="flash" name="empForm" wmode="transparent" onload="#onLoad#" style="#formStyle#" preservedata="yes" >
    <cfformgroup type="horizontal" style="marginTop:0; horizontalGap:15;marginRight:15;horizontalAlign:right">
                      <cfinput type="text" name="filterProjectInput" size="12" label="Filter: " onChange="_global.findProject({})" enabled="{gridCustomer.selectedItem != undefined}"/>
                   </cfformgroup>
    </cfform>

    file: as_dataManagement.as

    _global.findProject = function():Void {
       //fields are passed to component as a variable
       var Parameter = {};
       Parameter.filterText = _root.filterProjectInput.text.toLowerCase();
       mx.managers.CursorManager.setBusyCursor();
       Parameter.onStatus = function( stat: Object ):Void {
          //if there is any error, show an alert
          alert("Error while calling cfc:" + stat.description);
       }
       
       //get service
       netService = connection.getService(epmComp, Parameter);
       
       //find data with remoting
       netService.findProject(Parameter);
       
       //put the controls in scope to avoid calling _root
       var gridProject = _root.gridProject;
       
       Parameter.onResult = function( results: Object ):Void {
          //when results are back, populate the cfgrid
          gridProject.dataProvider = results;
          mx.managers.CursorManager.removeAllCursors();
       }
    }

    file: epmCFC.cfc

    <cffunction access="remote" name="findProject" output="false" returntype="Any">
          <cfargument name="filterText" type="Any" required="yes">
          
             <cfquery name="findProject" datasource="#session.datasource#">
                SELECT *
                FROM PROJECTS
                WHERE projectName LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#lcase(arguments.filterText)#%">
             </cfquery>
             <cfreturn findProject/>
       </cffunction>
  43. Michael White

    Michael White

    I am curious about the "#formStyle#" variable. I assume it is a structure. would you share that too?
  44. Mark Cadle
    Not to crack on the post there, but remoting for filtering is a poor idea. Every letter typed is making a call to the database....why??? All of the data has already been stored in the grid. Making a copy of that data and placing it in an array is much faster, convenient, less network traffic, as well as better performance on the page by memory management. I would highly NOT recommend do a remoting call just to filter a grid.
  45. Nahuel
    I agree 100% with Mark. It is not good to call the server each time a user enters a letter. You can kill the server if you have a lot of records :)
  46. Kevin Hunkovic

    Kevin Hunkovic

    Is there any way to the above example with an xml form instead of a flash form. I have gotten the above example to work perfectly however when you are dealing with large datasets say over 200 records the form takes 25 seconds to load. If I change the format of the form to xml instead of flash it the grid loads in 2 seconds. The filter functions no longer work of course.
  47. V Fusion

    V Fusion

    Joel Watson post (March 07)...
    "Currently, I can insert, update and delete when no filter is applied no problem (not an ideal solution), but when I try to filter, the functionality disappears and the submission sends a blank entry."

    I'm having the same problem. Does anyone know/have a fix? Thanks!
  48. Joe
    Is there a way to use wildcards to only look for characters in a certain position?
  49. Mark Cadle
    V Fusion, I assume you are using a cfgridupdate for your CRUD statements. If this is the case, when you modify the dataprovider of the grid, it breaks this functionality. To date, I do not know of a way to fix this. Maybe Laura will have insight, but most of us use remoting and manually write the CRUD SQL.

    Joe, the answer is yes! There are multiple ways of doing this. If you are wanting to do this as you type and only look for the characters you type in a specific point in the string, you merely need to modify the substring section where I have all caps, you would use 0 to start at the beginning or the number for your start point and then how many characters to look at. So to basically do w%rd it would be 1,1.
    CODE:

    if(item[selected].toString().substr(START_POINT_INTEGER,NUMBER_OF_CHARACTERS_TO_SEARCH_INTEGER).toLowerCase() == fortext)


    If you are wanting to search for a predefined list of characters in a predefined location, you would still use substr but would need to do it in a different function. Same goes for other variations but you can use search or match function.

    Lastly, if you are not doing this in actionscript you could use the ColdFusion function REFind which leverages Regular Expressions to match the pattern or just Find or do it in your query.

    Hope this helps.
  50. V Fusion

    V Fusion

    Thanks Mark (#52). I failed to see your earlier post (41). For the benefit of others using CFGRIDUPDATE, its best to disable the buttons when you have text in forInput. I had to disable two buttons. My solution:
    <cfsavecontent variable="submitIfClear">
       //forInput is the name of a textbox
       // deleteEntry and save are button names
       // everything is cAsE sensitive
    if(forInput.text != '')
    {
       deleteEntry.enabled = false;
       save.enabled = false;
    }
    else
    {
       deleteEntry.enabled = true;
       save.enabled = true;
    }
    </cfsavecontent>
  51. V Fusion

    V Fusion

    For the many AS newbies reading this site: I forgot to add one more piece - usage - to my previous post (#53)
    <cfinput type="text" name="forInput"
    width="120" label="Filter by:"
    onchange="#actionFilter#; #submitIfClear#" >
  52. Mike
    I am trying to use the filter function with flash remoting
    and I am having some success. Basically I have a grid
    with a cfselect drop-down menu that has columns from my table that is connected to the grid. I use this drop down to search by these columns. When I initially execute a search in the datagrid and then I apply my filter on the dataset search results the filter works great using 'results.items' as stated in above posts in the response handler. The problem is that when I execute another search and then apply the filter to the next dataset results the filter fails. Instead of the filter working on the newly returned dataset that came back to the datagrid from my subsequent executed search query the filter is still filtering the original dataset results from the 'first' time the search was executed. And all the data is being returned from a cfc through flash remoting on every search executed. So the filter works great on the first search run dataset but then after I get a new search dataset result it seems like the dataprovider or recordset object is not getting updated with the new dataset thus the filter is still only working on the original dataset result. Anyone run into this problem or have any ideas?
  53. Mike
    Ok, I just figured this one out with a little bit more digging. So disregard my previous post. Just had assign the _global variable to the new results in the response handler.


    Thanks,
    Mike