My Assistant
![]() ![]() |
|
|
Jun 4 2005, 03:30 AM
Post
#1
|
|
|
UtterAccess Addict Posts: 106 From: Philippines |
Hello fellow UA's
How can I filter a form based on the value selected in the 2 Listboxes and 1 option group(toggle button) ? Thanks! |
|
|
|
Jun 4 2005, 10:24 AM
Post
#2
|
|
|
UtterAccess VIP Posts: 20,187 From: Colorado |
put comboboxes, textboxes, listboxes, etc on the form (i put then in the header). Assign this to the AfterUpdate event of each one...
=SetFormFilter() then put this code behind the form CODE Private Function SetFormFilter() dim mFilter as string mFilter = "" If not IsNull(me.text_controlname ) Then mfilter = "[TextFieldname]= '" & me.controlname_for_text & "'" end if If not IsNull(me.date_controlname ) Then if len(mFilter) > 0 then mFilter = mFilter & " AND " mfilter = mfilter & "[DateFieldname]= #" & me.controlname_for_date & "#" end if If not IsNull(me.numeric_controlname ) Then if len(mFilter) > 0 then mFilter = mFilter & " AND " mfilter = mfilter & "[NumericFieldname]= " & me.controlname_for_number end if if len(mfilter) > 0 then me.filter = mfilter me.FilterOn = true else me.FilterOn = false end if me.requery End Function me.controlname_for_number refers to the NAME property of a control on the form you are behind (Me. represents the form -- kinda like "me" for me is not "me" for you (IMG:http://www.utteraccess.com/forum/style_emoticons/default/wink.gif) ) delimiters are used for data that is not a number quote marks ' or " for text number signs # for dates mfilter is a string that is being built for each condition -- but if nothing is specified in the filter control (IsNull), then that addition to the filter string is skipped. finally, when the filter string is done, it is applied to your form. That means that as you flip through records, ONLY records matching that filter will show Then, put another command button on the form Name --> btnShowAll OnClick --> [Event Procedure] CODE me.filteron = false me.requery a requery of the form will also reset the record pointer back to the first record. If you want to capture the record you are on and set it back, you can do this: CODE 'save value of primary key
dim mPrimaryKey as long mPrimaryKey = 0 if not me.newrecord then mPrimaryKey = nz(me.mPrimaryKey_controlname) end if me.filteron = false me.requery 'go back to record you were on if mPrimaryKey <> 0 then me.mPrimaryKey_controlname.setfocus docmd.findrecord mPrimaryKey end if me.controlname_for_whatever.setfocus |
|
|
|
Jun 4 2005, 10:43 AM
Post
#3
|
|
|
UtterAccess VIP Posts: 20,187 From: Colorado |
if your listboxes are single-select, you can use the code as written above. If your list boxes are multi-select, you will need to loop through them and construct an IN clause.
For your option group, you will need to test its value and, build the filter string according to what was chosen. ************ Multi-Select Listbox CODE dim mFilterList as string, varItem mFilterList = "" For Each varItem In listbox_controlname.ItemsSelected 'pick ONE of the 3 following statements 'if field is a number, no delimiter mFilterList = mFilterList & ", " & listbox_controlname.ItemData(varItem) 'if field is text, delimit with quotes mFilterList = mFilterList & ", '" & listbox_controlname.ItemData(varItem) & "' " 'if field is an date, delimit with quotes mFilterList = mFilterList & ", #" & listbox_controlname.ItemData(varItem) & "# " Next varItem if mFilterList ) > 0 then 'Take the comma off the beginning mFilterList = right( mFilterList, len(mUserCriteria )-2 ) 'see if the current filter string has anything -- if so, use AND to combine them if len(mFilter) > 0 then mFilter = mFilter & " AND " 'add the information to the current filter string mFilter = "AND [fieldname] IN (" & mFilterList & ") " end if **** Option Group CODE dim mFilterOption as string If not isnull(me.optionGroup_controlname) then SELECT CASE me.optionGroup_controlname CASE 1 mFilterOption = "..." CASE 2 mFilterOption = "..." CASE 3 mFilterOption = "..." CASE else mFilterOption = "..." END SELECT End If if len(mFilterOption) > 0 then 'see if the current filter string has anything -- if so, use AND to combine them if len(mFilter) > 0 then mFilter = mFilter & " AND " 'add the information to the current filter string mFilter = mFilter & mFilterOption end if |
|
|
|
Jun 4 2005, 08:40 PM
Post
#4
|
|
|
UtterAccess Veteran Posts: 301 From: Florida |
Hi Crystal,
Been watching your reply posts and saving several of them for later use. I admire you spending so much time helping others. For us beginners, it means so much. Thanks, AP |
|
|
|
Jun 4 2005, 08:47 PM
Post
#5
|
|
|
UtterAccess VIP Posts: 20,187 From: Colorado |
what a nice thing to say, thank you (IMG:http://www.utteraccess.com/forum/style_emoticons/default/wink.gif) happy to help
|
|
|
|
Jun 4 2005, 09:11 PM
Post
#6
|
|
|
UtterAccess VIP Posts: 18,396 From: Oklahoma City, Oklahoma |
Crystal,
Ditto to AP's comments. (IMG:http://www.utteraccess.com/forum/style_emoticons/default/notworthy.gif) Thanks for all the help you do for others. |
|
|
|
Jun 4 2005, 09:40 PM
Post
#7
|
|
|
UtterAccess VIP Posts: 20,187 From: Colorado |
Thanks, Boyd!
back at ya ... I have learned some neat tricks from your code |
|
|
|
Jun 4 2005, 10:30 PM
Post
#8
|
|
|
UtterAccess Addict Posts: 106 From: Philippines |
|
|
|
|
Jun 5 2005, 10:15 AM
Post
#9
|
|
|
UtterAccess VIP Posts: 20,187 From: Colorado |
you're welcome (IMG:http://www.utteraccess.com/forum/style_emoticons/default/wink.gif)
...just have to point out a couple things First, there is an error in the code mFilter = "AND [fieldname] IN (" & mFilterList & ") " SHOULD NOT HAVE "AND" IN IT since the statement above puts it in if necessary --> change to CODE mFilter = "[fieldname] IN (" & mFilterList & ") " also it is a good idea to output the constructed filter to the debug window before it is actually applied -- at least while developing -- this allows you to open the debug window and make sure your filters are correctly constructed and, if there is a problem -- like the filter is not applied -- you can examine the string and correct the problem CODE 'output filter to debug window before applying Debug.Print mFilter if len(mFilter) > 0 then '... press CTRL-G to Goto the debug window --- Whenever you write or paste code, your should ALWAYS compile it before you attempt to run it. from the menu: Debug, Compile fix any errors on the yellow highlighted lines keep compiling until nothing happens (this is good!) |
|
|
|
Jun 5 2005, 10:39 AM
Post
#10
|
|
|
UtterAccess VIP Posts: 20,187 From: Colorado |
it is ALSO a good idea to include an error handler in your code
ERROR HANDLER CODE '------------------------ put this line at top of procedure: On Error GoTo procedurename_Error '... other statements '------------------------ add these lines to the bottom of the procedure 'if everything executed normally, exit the procedure 'Exit sub -- use if the procedure is a Sub Exit Function procedurename_Error: MsgBox Err.Description, , "ERROR " & Err.Number & " procedurename" 'press F8 to step through lines of code to see where problem is Stop Resume if, during execution, an error flag is raised, execution will go to the error handler, which is denoted with a line label procedurename_Error: is a line label -- you can change the name before the colon -- but you cannot have the same line label twice in the same module sheet. So, in this case, your procedure name is "SetFormFilter", so your line label would be SetFormFilter_error: and your message mox statement would say MsgBox Err.Description, , "ERROR " & Err.Number & " SetFormFilter" and the line at the top to initalize the error handler would say On Error GoTo SetFormFilter_Error once the execution goes to the error handler, a message box is issued describing the problem, and then the code is STOPped with Stop Press the F8 key ( which is the shortcut key to single-step through code) once to go to the next line Resume tells the process to go back to the line that caused the problem. press F8 again to go to the actual offending line. In this case, it would probably be me.filter = mfilter and that would be because something is wrong with the filter string at that point, you could open the Debug Window and examine the string. You can then fix the problem, save your code, and then resume the code at the top where mFilter is set to "" (right-click on the line you want to resume with mFilter = "" and choose "Set Next Statement" from the shortcut menu) then, either F5 to RUN (from the menu bar: Run, Run) or F8 to continue stepping through code OR to stop the procedure (from the menu bar: Run, Reset) if, at any point during execution, you want to STOP the code, press CTRL-BREAK -- you may have to hold the Control key and repeatedly press the Pause/Break key until Access pays attention to the keyboard. In your code, you can put in a line that MAKES it pay attention to the keyboard: DoEvents If I have a loop, I often put DoEvents into the loop while I am developing. Sometimes DoEvents is necessary to make changes "stick" -- like if you are writing to a form from code that is not behind the form, or changing data with an SQL statement. |
|
|
|
Jun 6 2005, 08:57 PM
Post
#11
|
|
|
UtterAccess Addict Posts: 165 From: Oregon |
Just wanted to say thank also Crystal, I came searching for help with combining options with a combo box selection and I think this would work great.
You put a lot into extra effort in your responses and us newbies are very thankful for your help. Mary |
|
|
|
Jun 6 2005, 09:30 PM
Post
#12
|
|
|
UtterAccess VIP Posts: 20,187 From: Colorado |
thanks, Mary (IMG:http://www.utteraccess.com/forum/style_emoticons/default/wink.gif) ... Welcome to Utter Access
|
|
|
|
Jan 22 2006, 10:40 AM
Post
#13
|
|
|
New Member Posts: 7 From: Baltimore, MD |
Crystal,
Just wanted to chime in -- I am a real Access newbie and finding this post has made my filtering so much easier-- my heartfelt thanks! Best regards, Nina |
|
|
|
Jan 22 2006, 02:21 PM
Post
#14
|
|
|
UtterAccess VIP Posts: 20,187 From: Colorado |
thank you, Nina (IMG:http://www.utteraccess.com/forum/style_emoticons/default/wink.gif) happy to help
Welcome to Utter Access |
|
|
|
Mar 19 2008, 01:02 PM
Post
#15
|
|
|
UtterAccess Guru Posts: 886 From: Greenville, SC |
I want to bring up this old post, particularly Crystals first response. I am having trouble understanding.
If you put =SetFormFilter in the After_Update event of each control you want to filter by, then it would seem you would have to have code in Function SetFormFilter() to process every one of the control names. Or you could pass the control name to the function, though I don't know how to do that. Can anyone shed a little light on this? I was told I should hard code the control name after the Me. If I run the function in the after_update event of each control, it will have no way of knowing which control fired it - I think. Let's say I have 3 comboboxes, ComboA, ComboB, and ComboC and I want to filter the form on all 3. Is it possible to add to the filter with each subsequent Combobox selection? That is, make a selection from ComboA which filters it on ColumnA in the dataset, then ColumnB which further filters it, and then ColumnC, which narrows it down yet further. OR, I could have the user make his selections, and then build the multiple-criteria filter in one shot after a button is pushed. But I am not sure of the synatax for that, either. |
|
|
|
Mar 19 2008, 06:05 PM
Post
#16
|
|
|
UtterAccess VIP Posts: 20,187 From: Colorado |
Hi Duane,
"f I run the function in the after_update event of each control, it will have no way of knowing which control fired it - I think." you CAN know that information ... with Me.ActiveControl.Name (not that it really matters much) "Is it possible to add to the filter with each subsequent Combobox selection? " if your combos are cascaded such that, if C is filled then A and B don't matter, or if B is filled then A doesn't matter, you could do something like this: CODE if isnull(me.comboC) then if IsNull(me.comboB) then if IsNull(me.comboA) then me.filterOn = false else me.filter = "[field] = " & me.comboA me.filterOn = true endif else me.filter = "[field] = " & me.comboB me.filterOn = true endif else me.filter = "[field] = " & me.comboC me.filterOn = true end if me.requery WHERE comboA, comboB, and comboC are the control Names of the respective controls if the data type of your fields are not numbers, you will need to concatenate delimiters CODE me.filter = "[text_field] = '" & me.controlname & "'"
'or me.filter = "[date_field] = #" & me.controlname & "#" |
|
|
|
Mar 19 2008, 06:07 PM
Post
#17
|
|
|
UtterAccess VIP Posts: 20,187 From: Colorado |
WHERE
text_field a field name in your RecordSource whose data type is text date_field a field name in your RecordSource whose data type is date/time |
|
|
|
Mar 20 2008, 09:53 AM
Post
#18
|
|
|
UtterAccess Guru Posts: 886 From: Greenville, SC |
So, on that code at the very top of this post, I suppose you could make it into a function and pass Me.ActiveControl.Name to it and maybe programmatically determine whether it was a data or number or text and then apply the filter accordingly?
|
|
|
|
Mar 20 2008, 11:12 AM
Post
#19
|
|
|
UtterAccess VIP Posts: 20,187 From: Colorado |
Hi Duane,
no, you would not need to pass the Activecontrol. In a general procedure, it is: Screen.ActiveControl.Name I would not recommend putting filtering stuff into a general module though, use CBF (code behind the form) because, in addition to data type(s), you need to get the fieldname(s) right |
|
|
|
Mar 21 2008, 05:30 PM
Post
#20
|
|
|
UtterAccess Guru Posts: 886 From: Greenville, SC |
I must be really missing something here. I will quote the code at the beginning:
CODE Private Function SetFormFilter() dim mFilter as string mFilter = "" If not IsNull(me.text_controlname ) Then mfilter = "[TextFieldname]= '" & me.controlname_for_text & "'" end if If not IsNull(me.date_controlname ) Then if len(mFilter) > 0 then mFilter = mFilter & " AND " mfilter = mfilter & "[DateFieldname]= #" & me.controlname_for_date & "#" end if If not IsNull(me.numeric_controlname ) Then if len(mFilter) > 0 then mFilter = mFilter & " AND " mfilter = mfilter & "[NumericFieldname]= " & me.controlname_for_number end if if len(mfilter) > 0 then me.filter = mfilter me.FilterOn = true else me.FilterOn = false end if me.requery End Function OK. We put this code behind the form. Let's say I have a textbox called MyDCWtext, MyDCWnumber, and MyDCWdate, just to make sure I don't mis-interpret your naming conventions here. And let's say I am filtering on these 3 textboxes on the same form with this one function behind it. You say to put =SetFormFilter in the After_Update event of each of these 3. Now, it seems to me, that you would have to either 1) change the code from me.controlname_for_text to Screen.ActiveControl, or 2) hard-code one function of a different name for each of these textboxes and hardcode the name of the textbox in the function (ie: Me.MyDCWtext instead of me.controlname_for_text), or 3) have a decision loop inside the function to determine which textbox was being processed at the time (ie, something like If screen.activecontrol.name = MyDCWtext then .... else me.activecontrol.name = Me.MyDCWnumber then ...., etc.). So what gives here? I am afraid I just don't understand. Thanks for your patience and replies here. |
|
|
|
![]() ![]() |
|
Go to Top · Lo-Fi Version | Time is now: 19th May 2013 - 02:29 AM |