UtterAccess.com
X   Site Message
(Message will auto close in 2 seconds)

Welcome Guest ( Log In | Register )

3 Pages V   1 2 3 >  
Reply to this topicStart new topic
> Filter a form via two 2 Listboxes and 1 option group    
 
   
Isaigi
post 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!
Go to the top of the page
 
+
strive4peace
post 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
Go to the top of the page
 
+
strive4peace
post 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
Go to the top of the page
 
+
MiaAccess
post 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
Go to the top of the page
 
+
strive4peace
post 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
Go to the top of the page
 
+
HiTechCoach
post 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.
Go to the top of the page
 
+
strive4peace
post 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
Go to the top of the page
 
+
Isaigi
post Jun 4 2005, 10:30 PM
Post #8

UtterAccess Addict
Posts: 106
From: Philippines



Thanks for the help!
(IMG:http://www.utteraccess.com/forum/style_emoticons/default/notworthy.gif) (IMG:http://www.utteraccess.com/forum/style_emoticons/default/notworthy.gif) (IMG:http://www.utteraccess.com/forum/style_emoticons/default/notworthy.gif)
Go to the top of the page
 
+
strive4peace
post 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!)
Go to the top of the page
 
+
strive4peace
post 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.
Go to the top of the page
 
+
annalyst
post 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
Go to the top of the page
 
+
strive4peace
post 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
Go to the top of the page
 
+
nrkarp
post 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
Go to the top of the page
 
+
strive4peace
post 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
Go to the top of the page
 
+
duanecwilson
post 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.
Go to the top of the page
 
+
strive4peace
post 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 & "#"
Go to the top of the page
 
+
strive4peace
post 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
Go to the top of the page
 
+
duanecwilson
post 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?
Go to the top of the page
 
+
strive4peace
post 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
Go to the top of the page
 
+
duanecwilson
post 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 the top of the page
 
+

3 Pages V   1 2 3 >
Thank you for your support! Reply to this topicStart new topic

Jump To Forum:
 



RSS Go to Top  ·  Lo-Fi Version Time is now: 19th May 2013 - 02:29 AM