Our Blog

Or "Why I love functions".

In my previous post, Quick grid bindings, I showed how to use a custom function, applyFilter, that I had described earlier.

Some readers asked how to change the first grid to a tree, then to a dropdown. Just because I like to be ahead of things, and to show how easy is to reuse a function once you have created it, I threw in a repeater with radio buttons as well.

All three controls, dropdown, tree and radio button group filter the same grid, but they could use different grids if you wanted them to (just change the reference to the grid, contactList). Notice that they all call the same function, but pass different parameters with respect to what the term to filter by should be.

<!--- departmentSelect.selectedItem.data --->
<cfselect name="departmentSelect" query="departmentsQuery" display="name" value="id" onchange="applyFilter(departmentSelect.selectedItem.data, contactList, ['department'])" queryposition="below">
   <option value="">Department</option>
</cfselect>
<!--- departmentTree.selectedNode.getProperty('data').value --->
<cftree name="departmentTree" onchange="applyFilter(departmentTree.selectedNode.getProperty('data').value, contactList, ['department'])">
   <cftreeitem display="name" query="departmentsQuery" value="id">
</cftree>
<!--- departmentOption.selectedData --->
<cfformgroup type="repeater" query="departmentsQuery">
   <cfinput type="radio" name="departmentOption" value="{departmentsQuery.currentItem.id}" label="{departmentsQuery.currentItem.name}" onclick="applyFilter(departmentOption.selectedData, contactList, ['department'])">
</cfformgroup>
</cfformgroup>

<cfgrid name="contactList" query="contactsQuery" rowheaders="false">
   <cfgridcolumn name="name" header="Employee Name">
   <cfgridcolumn name="gender" header="Gender">
   <cfgridcolumn name="age" header="Age">
</cfgrid>

Note: For those who have not followed previous posts, the above code is not complete, you need to add the applyFilter function code. Or download the source for the complete code.

Live example

Download the source

Laura

Laura

63 Comments

  1. Bob
    Hi, I have a questions regarding the filtering function and flash remoting. I have a grid that gets results from a query when the page loads. If I use your filter function with the on load query results it works like a charm. Next a user can search a database, results are returned from flash remoting, populating the grid. If i use the filter function on the search result, the grid it reverts to the original (on load) query. My question is how can i filter a grid populated with query results from flash remoting ?
  2. Chikowski

    Chikowski

    I love what you guys are doing. I have a question with this new way of binding things together. Is it possible to bind a select to an input? Kinda like you guys had in the address book app. Instead of selecting a name from a grid and showing all the info, instead use a select. I know it couldn't be done in the past but is it possible to do it now with this new release?
  3. Michael White
    I have been hoping you would come up with a routine like this so I can filter my contacts grid by ContactTypeID (Manager, Contractor, Temp, etc.) but I find it difficult to modify this script because both contacts and departments use 'id' as the identifier column and since I'm such a newbie I have to play around to figure out which is ContactID and which is DepartmentID. This one is really gonna help me out once I fight my way through the syntax.
  4. Michael White
    I am trying to adapt this routine to my purposes and i just left the grid.id the way it was and it seems to be working... I guess the id in this case is neither the contact &quot;id&quot; nor the department &quot;id&quot; but a keyword thingy. that brings up my second problem... I know you're making this routine as flexible as possible but since I am using straight integer values from a cfselect to filter the grid, it has to match exactly, not merely &quot;contain&quot;. Maybe what I'm asking it so simple I don't need this fancy routine?
  5. Michael White

    Michael White

    Ok, once I get this all figured out, this is going to be the end result, the final filtering problem for my grids... this is it: I need to have both the filter as you type and the filter by select working together on the same grid to, say filter by department using a cfselect, then filter that result by typing part of the person's name. or perhaps it might be more useful to go the other way... type part of a person's name and filter those names by department. Doesn't that sound like fun?
  6. Michael White
    I guess it took a good night's sleep, a cup of coffee in the morning and an english muffin, but here's another useful idea: Say I have a list of 300 contacts that grows at a rate of 50 per week. Some contacts go away but I don't want to delete them because I need the historical reference. To solve this I mark them active with a bit datatype in SQL. I want to be able to filter by name (as you type) and choose active or inactive or both from checkboxes... oh, and wouldn't it be nice to filter by department, too? Now I'd be able to find all the active contacts in the finance department that start with the letter &quot;S&quot; because I don't know if she spells her name Shelly or Rochelle, I keep the other parameters and just change the S to an R
  7. Hi Michael,
    A quick solution could be adding some logic to the filter function.
    You can add an &amp;&amp; and check if the person starts with the letter &quot;A&quot; &amp;&amp; is in deparment &quot;C&quot;
    For example:
    if(value.indexOf(filterTerm) != -1 &amp;&amp; your_new_code_here)
    {
    filteredData.push(item);
    added = true;
    }
  8. William
    Any idea how I can filter my grid onload?

    Instead of having the grid show ALL records, I need my grid to be empty until the user selects an option from the combobox.

    I've tried calling an onload AS function with &quot;mygrid.dataProvider = [];&quot; in it, but it seems the grid is actually populated from my query AFTER the onload event.

    Thanks in advance!
  9. In response to my own post above, here is the workaround I came up with. OnLoad I set mygrid.visible = false; to hide the grid. OnChange of the combobox I set mygrid.visible = true;

    There is still a bit of lag time after selecting your first combobox choice during which the user's machine filters the list and the user sees everything. However, if your cfgrid list isn't too long it is hardly noticeable.
  10. multipleselectboxesmemory

    multipleselectboxesmemory

    Multiple Select Boxes and you want it to remember SelectFilterA while you SelectFilterB.
  11. Laura
    William,
    The answer to your question:
    http://www.asfusion.com/blog/entry/knowing-when-the-cfform-data-arrives
  12. Laura
    Bob (second commenter),
    The filter function saves the dataprovider the first time it is called assuming it will never change. If it does, then you will need to update the variable that holds it so that it gets the new data.
    _global.unfilteredData['myGrid']
  13. Michele

    Michele

    Laura &amp; Nahuel,

    Thanks so much for all the great examples. I am new to all this and building an app based on the address book example. My edit form has some radio buttons with hard coded values and I cannot figure out how to bind them to the grid. This seems to be a common issue as I've found questions about this in other blogs but no answers. Any assistance is much appreciated.
  14. Hi Michele,
    You can add this code in the &quot;onChange&quot; event of your grid:
    myRadio.selectedData = myGrid.selectedItem.YourColumnName;
  15. Michele

    Michele

    Thank you, Nahuel, for the speedy reply. It works and you saved me a lot of time!
  16. Giovani

    Giovani

    Hi, folks. I'm new to CFForm/Flash and I have a question to make. I have a CFGrid with two tabs. On the first, the user enters some data and clicks on a button, which brings the related data from the database. On the other tab, I have a CFGrid that displays the results of the previous search. It happens that I have a second button on which the user clicks to send one selected row to another page (action page that does additional things). I used to do this in JavaScript changing the action of the form on the onclick event of each button and then used submit() to go to the right page. Now, how can I do this in CFForm/Flash? The best I could do was to set a CF variable and change the action of the cfform, but I can do this only one time (when the page loads). This way, I can change the action of the cfform, but both buttons go to the same action page. As I'm doing two different things on the same page, I need two different actions (one to each button). I could have two cfforms on that page, but this way I couldn't group them on tabs. Any ideas? Thanks, Giovani.
  17. Laura
    Giovanni,
    You can have a button with onclick=&quot;getURL('your page')&quot;, appending any data that the page needs (as long as it is short, since it is a get request)
    There is no way to change the action page after the form is loaded.
  18. Laura
    Chikowski (third comment)
    It is not possible because the cfselect still contains only data and label, lacking all of the other columns.
    However, you can use this technique (http://www.asfusion.com/blog/entry/knowing-when-the-cfform-data-arrives ) to load the cfselect data onload with remoting, and then you will have all the columns you need.
  19. Michele

    Michele

    Hi Laura &amp; Nahuel,
    I love this filter function! It was so quick to implement and I did not have to modify the script at all. I'm trying to do something similar to Michael - I'm using 3 radio buttons to filter grid by active records, inactive records and all records. Active and Inactive options are working perfectly, but I cannot figure out how to assign Active AND Inactive as value for the All option. Is this possible?
  20. Michele

    Michele

    Well, I figured a workaround for the All option. By forcing the first if statement to fail, the grid is not filtered and shows all records. Now I'm trying to combine your quick bindings example and the filter functions. I'm using radio buttons bound to grid to show active, inactive or all records - by using your filter function. I also want to be able to search for a text string in a specific grid column. They're both working, just not with each other. As soon as I search a column, the grid defaults to all records regardless of the active, inactive or all filter selection. Any ideas? Can these be combined?
  21. Michele

    Michele

    I love this function, but I could not figure out how to filter my records and then search for a text string in a specific column, for the filtered records only. Soooo, I went back to 2 older examples - filtering records on a cfform grid and filtering a grid as you type in a cfform, which both use a very similar cfsavecontent tag. I was able to combine these and achieve the desired effect. If anyone wants to see the code, I posted it on the filtering a grid as you type in a cfform blog. I still would rather use the function because I have a hunch it's more efficient, but I couldn't figure it out.
  22. Michael

    Michael

    I have added this fucntionality and it works great. I enabled editing of the data in the grid, but when I filter, edit, and then submit the form the data does not come over. If I just load the form and edit without filtering The data is submitted. Any ideas?
  23. Steve Walker
    I am trying to build a new calendar form and I can't figure out how to call a function using cfcalendar and passing a date. Any suggestions/solutions.
  24. Steve Walker
    Ok, so I figured out that

    myService.getEvents(cal.selectedDate);

    will pass the date (Flex docs rock). Now I am having a heck of a time trying to bring back a list of events between a date range (+/- 7 days) from the date selected. Anybody done something like this?
  25. Jan
    Hi all,

    I am pretty new to this all and just upgraded to MX7 (including the latste update). I used this code and several other examples and the flash forms do show up. But they never show any data, they remain empty ! That little clock is turning forever. I use simple cfquery statements and cfdump shows all data when I test on my win 2000 server. Any suggestions ?
  26. Laura
    Jan,
    That means you have a problem with your Flash Remoting installation. Check the last paragraph of this post for help on how to set it up:
    http://www.asfusion.com/blog/entry/introduction-to-flash-remoting
  27. Neil Huyton

    Neil Huyton

    Hi Laura.

    Can you expand on the solution you gave Bob for applying the filter to a grid populated with remoting.

    You said that you need to update the variable that holds the unfiltered data so that it gets the new data.
    _global.unfilteredData['myGrid']

    Does this need to be done on the onResult so:
    _global.unfilteredData['myGrid'] = results;

    Is this along the right track?

    Thanks.
  28. Laura
    Neil,
    That's correct assuming the results contains a query. However, the filtering will not work if you just do _global.unfilteredData['myGrid'] = results;
    Use
    _global.unfilteredData['myGrid'] = results.items;
    instead.
  29. Michael White
    Nahuel kinda answered my question of 10-1-05 on 10/3/05 but now I'm actually gonna try to get this thing working. In your example none of the department ID values are more than one digit so it seems to work but when you have numbers like 14, 114, 141, 142, etc, they all show up. How do I get the routine to filter the second grid by exact ID values from the first grid?
  30. Laura
    Michael,
    indexOf() looks in any part of the string. You need to change it to an == condition
    You should be able to find an example of that in the comments of the many filtering examples we have.
  31. Ed Welch

    Ed Welch

    Can a selecteditem from a grid be binded to the selected item in a cfselect statement?
  32. Laura
    Ed,
    Not directly. If I understand correctly what you want, you can see an example of that in the Real Estate sample app. That part specifically is explained in the article:
    http://www.asfusion.com/blog/entry/coldfusion-flash-forms-macromedia-2
  33. Brian
    Is there an example for using checkboxes in a repeater block? In the example above, I would like to be able to check multiple departments and have the results for each department that is checked appended to the grid.
  34. Pete
    This is great, and I appreciate your efforts and your willingness to share these techniques with the community.

    I need to take this to the next level; I would like to be able to filter on more than one row; for instance, assume a CFGRID with gender, first name, and last name. I would like to be able to first filter by gender using a SELECT, and then be able to filter on first name from a SELECT; so, if I select &quot;Male&quot; as the gender, and &quot;Peter&quot; as the first name, that should display just those males named Peter.

    Is this difficult or even possible?
  35. Michael White
    Giovanni asked a question a few months ago which you answered with getURL('page.cfm'). I would like to know what the syntax would be to add a url variable bound to the selected item of a grid. get(URL('page.cfm?ContactID=gridContact.selectedItem') kind of thing and would it error before a selection is made?
  36. Michael White
    I tried the following:
    onclick=&quot;getURL('ContactMgr.cfm?ContactID={gridContact.selectedItem.ContactID},'_blank')&quot; but it sends the literal string, not the value... help...
  37. Michael White
    ok, I think I figured it out using Ray Camden's post about opening a new window.
    I have a javascript routine to open the window:

    &lt;script&gt;
       function show(u) {
          if(u != '') window.open(u, 'sub', 'directories=no, location=no, menubar=no, resizable=yes, scrollbars=no, status=no, titlebar=yes, toolbar=no, height=435, width=535')
       }
    &lt;/script&gt;

    Then I have a grid called &quot;gridContact&quot; and the ID for contacts is ContactID so the syntax for the onload event looks like this:

    onclick=&quot;getURL('javascript:show(\'ContactProfile.cfm'+'?ContactID='+gridContact.selectedItem.ContactID+'\')')&quot;
  38. Ed Welch

    Ed Welch

    Try this....
    onclick=&quot;if (queResults.selectedItem.id &gt; 0 ) {getUrl('PrintForm.cfm?PQCProfileID=' + queResults.selectedItem.id,'_blank');}&quot;

    This will open a html page in another window...and it will make sure that the id is greater than zero first...
  39. Michael White
    Thanks Ed, I'll try that, it looks simpler when you don't need to control the header, toolbars and dimensions
  40. Hi,
    this is very awoseme stuff.
    I'm very new to flash forms and this particular demo hit the spot on what I to do.
    However, I downloaded the sample and try to just switch components to get the data from my database and now the application doesn't work.

    I've got a table called departments and another divisions, from there I grouped the cftree to display department parent, division child.

    On the value for the cftreeitem, I've changed the value to divID (instead of the id that was there).

    My cfgrid is populated by my Employee table which is related to the division table by divID.

    Any ideas on why this doesn't work?
    Any suggestions?

    Thanks in advanced.
  41. SIMON
    if i use a repeater for my checkboxes, how do i reference them in my function so i can pass them to a cfc? There should be a comma seperated list of all values but I cant find the syntax
  42. Laura
    Simon,
    There is no comma-separated list you can use. They are in arrays.
    Say you have a text input inside your repeater called &quot;myTextInput&quot;, then you would get an array with the same name that contains each repeated text input. You would reference the contents like this:
    myTextInput[i].text where i is an index, probably a loop index.
    The same with checkboxes, but use .value (which will give you true/false), if you need something like an id, then you would get that from the repeater's dataProvider as in (id is a column of your query):
    myRepeater.dataProvider[i].id
  43. Todd
    I am successfully using a cftree to bind to my grid and filter data. I am trying to take it a step father and allow my users to edit the grid. Editing works fine if I only "touch" the grid when the page loads, but if i use my the cftree to filter the grid the form variable Form.mygrid.rowstatus.action comes back empty even though I have made multiple changes to the grid.
    Any ideas?
    Thanks in advance
  44. Laura
    Todd,
    See the second paragraph of this post:
    http://www.asfusion.com/blog/entry/filtering-a-grid-as-you-type---using
  45. Eric
    Is there a way to bind a textarea to a gridColumn?
  46. Laura
    Eric,
    The real estate tutorial explains how to bind each control type, including textareas: http://www.adobe.com/devnet/coldfusion/articles/flashforms_pt2_03.html
  47. Steve Willems

    Steve Willems

    Hi,

    First of all thanks for this incredible source for information on power design with cfform.

    I have a weird problem so I hopefully someone can give me a lead.

    When I populate my grids with from the DB using the query attribute of cfgrid it's impossible afterwards to access the dataprovider's columns after a slice (or by manual copy in a loop) to a global object. It always return an empty result.

    Now the strange thing is when I manually populate the rows using cfgridgrow with a loop it works fine. I can filter without problems.
    But..when I use this techinque no information is passed to the action page (using a post)

    <cfformitem type="script">
    function populateGrid( destgrid:mx.controls.DataGrid, grid:mx.controls.DataGrid, filter:String ){   
       if(_global.unfilteredData == undefined){
          _global.unfilteredData=[];
          for(var i:Number = 0; i < grid.dataProvider.length; i++) {
             _global.unfilteredData.push(grid.dataProvider.getItemAt(i));
          }
       }
       
       var filteredData:Array = [];

       for(var i = 0; i< _global.unfilteredData.length; i++) {
          if( _global.unfilteredData[i].userid == filter || filter=='All'){
             var a = filteredData.push(_global.unfilteredData[i]);                        
          }
       }

       destgrid.removeAll();
       destgrid.dataProvider = filteredData;
    }
    </cfformitem>


    So I'm kinda stuck...anyone an idea what might be the cause ? A Bug ? Or just a problem with my code ?

    Thanks for your help!
    Steve

    Oh yes...I'm running on a 7.0.1 server (but on our 7.0.2 test server I have the same problem)
  48. Laura
    Steve,
    I am not sure what the problem you are experiencing is. I don't think there should be a problem accessing the properties (columns) of the objects inside the array after a slice. However, most of these techniques make form "posts" fail, since we are manually changing things that do not call the methods that update the hidden inputs (by which the form knows what happened in flash)
  49. Chris
    Hi everybody, Love the examples on the site and they're answering a ton of questions.

    I'm am new to this so forgive me if this question sounds ignorant. I have an app that is used for people to enter their project time for a given week. I have a repeater section with three text boxes and a combo box for each time entry for the given week. My question is - is it possible to dynamically add a new row to a repeater section without submitting back to the server (either through remoting or local array manipulation)?

    Thanks in advance for the help,
    Chris
  50. Henam
    Dear Laura,

    How can I change the function ApplyFilter for filtering a single value, there is, if the value was somethingID=1 from a first grid, the second must return only the results that matches exactly with the number 1. When I use your function posted here, it will bring me 1, 11, 21, 31, etc, all results with number 1.
  51. Henam
    Sorry I forgot, I already have tried indexOf() but I have not succeeded, could you write a small block o code with it ?
    Tanks Again...
  52. Maggie
    As always, I love what you guys are doing. I am definitely getting into Flex, but I have the need to use Flash Forms instead right now. That said, help! I am trying to implement this example, nothing fancy whatsoever. The data is not filtering based on the selection however - actually it looks like it's refreshing the data, but it does not filter.

    This is what I'm using:

    <cfquery name="statusQuery" datasource="#dsn#">
    SELECT changestatusid, status, sortorder, active
    FROM table
    </cfquery>   


    <cfquery name="changeQuery" datasource="#dsn#">
    SELECT table2.status, table1.changeid, table1.changetitle, changetype.changetype,
        table1.changestatusid, table1.trackingnumber, table1.datesubmitted,
    FROM table1
    INNER JOIN table2
    ON table1.changestatusid = table2.changestatusid
    INNER JOIN table3
    ON table1.changetypeid = table3.changetypeid
    </cfquery>   

    <cfformgroup type="horizontal">
    <cfformgroup type="vbox" width="200">
    <cfselect name="statusSelect" query="statusQuery" display="status" value="changestatusid" onchange="applyFilter(statusSelect.selectedItem.data,changeList,['changestatusid'])" queryposition="below">
    <option value="">Status</option>
    </cfselect>
    </cfformgroup>

    <cfgrid name="changeList" query="changeQuery" rowheaders="false">
    <cfgridcolumn name="status" header="Status">
    <cfgridcolumn name="trackingnumber" header="Tracking Number">
    <cfgridcolumn name="changetitle" header="Change Title">
    <cfgridcolumn name="datesubmitted" header="Date Submitted">
    </cfgrid>
    </cfformgroup>

             
    </cfformgroup>

    Am I missing something terribly obvious??
  53. Tad
    Laura,
    Perhaps you can shed some light on this for me. I am very new to CF Flash Forms but would like to make use of them in one of our applications. I'd like to have a panel on the left use a list of radio buttons that apply to different maintenance tables. As a user selects one of the buttons, the top right preview panel would display all the columns in the table selected. Selecting one of the columns from the preview panel would then allow the user to edit or delete the information in a bottom right panel. A button would also be available in the bottom right panel to add a new value to that database table. Is this something that is doable? I've looked at your examples but cannot figure out how to code the radio buttons and applyFilter function to bring up the applicable database table. Also, is there an advantage of doing this with remoting services? I've looked at the Real Estate example and am trying to utilize this type of look and feel. Thanks for any help you can provide.
  54. Scott
    The top level in my cftree is a list of vendors and the second level is a list of invoices associated to that vendor. Both of the levels are dynamically populated with results from a query.

    The cfgrid has a vendor and an invoice column? How do I set up the filter to bind by vendor if the user selects the top level and by invoice if the user selects the second level?
  55. Scott
    The top level in my cftree is a list of vendors and the second level is a list of invoices associated to that vendor. Both of the levels are dynamically populated with results from a query.

    The cfgrid has a vendor and an invoice column? How do I set up the filter to bind by vendor if the user selects the top level and by invoice if the user selects the second level?
  56. Kim
    Hi,
    I am new to Coldfusion Flash forms. I'm trying to create a page similiar to the contacts page. I am populating a cfgrid from a CFC passing it 2 parameters. When a user selects a row from the grid I want to populate the panel on the right which I have set up as tab pages since there is a lot of detail data. I have this part working. My problem is with the cfgrid, the columns that I have to display can't be grouped so when I select a row I'm not gett all of the data displayed.

    There is a primary key associated with row that is a seq. generated number in the database (PK), that I don't want displayed. The columns that I need to display are replicated ie.

    Grid list:
    PK(hidden) rec# col1 col2
    1 120 ab abc
    1 120 ab efg
    1 120 df abd
    2 121 ab gji
    2 121 fg ere

    Columns 1 and columns 2 are from separate tables joined via the PK where there is a many to one relationship.When I select rec# 120 I want to select all of the data associated with PK 1 which would include 3 rows.
    I think I need to use the onChange event on the cfgrid using the PK to get the information from the database to be displayed in the tab pages, but I haven't been able figure this out. Do I need another query or can I requery the same query used in the cfgrid passing it the PK. I'm formatting the data in the <cfsavecontent> tag. Is there a way I can bind using the hidden column and pull all of the necessary data?

    Any suggestions would be appreciated. Thanks
  57. John Beasley
    Laura,

    I was wondering if it is possible to bind two select boxes together. For example, I am working on a form that grabs all of the courses currently being taught in one select box, and based off of the selection of that box, another query will run to populate a second select box based on the value of the first. The second select box, shows the instructors that are currently teaching that course.

    In essense, they are dynamix select boxes. I am pulling the data from an Oracle DB using 2 cfquery statements. Is there any way you can think of applying this bind technique easily to my situation?

    Thank you so much and keep up the great work!
    John Beasley
  58. John Beasley
    Laura,

    I was wondering if it is possible to bind two select boxes together. For example, I am working on a form that grabs all of the courses currently being taught in one select box, and based off of the selection of that box, another query will run to populate a second select box based on the value of the first. The second select box, shows the instructors that are currently teaching that course.

    In essense, they are dynamix select boxes. I am pulling the data from an Oracle DB using 2 cfquery statements. Is there any way you can think of applying this bind technique easily to my situation?

    Thank you so much and keep up the great work!
    John Beasley
  59. Garcia
    Hi, im having trouble in binding 2 grids together.

    What im trying to do is when a user selects a row in the first grid an click on the add button, i want that the data of the row be passed to the other grid.

    any help wil be apreciated
  60. Garcia
    Hi, im having trouble in binding 2 grids together.

    What im trying to do is when a user selects a row in the first grid an click on the add button, i want that the data of the row be passed to the other grid.

    any help wil be apreciated
  61. Scott
    Is it possible to update a repeater form group dynamically with flash remoting? If so, how? Thanks!