I have an Access web database
In this database, I have a web form with a button on it
In its on-click event macro, it calls RunMacro Macro1 (client-macro) which fires successfully
in Macro1, if I call RunCode Function Name: DoTest() it returns the error: "The function you entered can't be used in this expression... Error Number 2426 (or 2950 if I have an "=" symbol in front of my function)
This issue is easily reproduced by doing these steps:
Create a blank web database in MS Access
Add and save a table
Create a default form from that table and put a button on it
Create a new VBA module "Module1" and put the following function in it:
Public Function DoTest()
MsgBox "Test function runs smoothly"
End Function
Create a client-macro "Macro1" with RunCode: Function Name: DoTest() (Note that IntelliSense recognizes the macro, and it runs fine from here)
Create the form's button's on-click macro event RunMacro: Macro Name: Macro1
Click the form's button from form-view to receive the error:
The function you entered can't be used in this expression.
You may have used a DoEvents, LBound, UBound, Spc, or Tab function in an
expression.
You may have used an aggregate function, such as Count, in a design grid or in a calculated control or field.
Clicking "Ok" shows error number 2426 or 2950 depending on if you have an equals sign before your function name or not in the client-side macro's RunCode command.
I've tried all of the tips from this very similar question without any luck. Access seems to find the function fine, as replacing the function name with gibberish gives a very different error.
What the heck am I doing wrong?
In my actual web database which uses Access Services published to SharePoint 2010, I use an If IsClient() Then macro statement on the form's button's on-click event to ensure that the VBA is only running in the client mode, but that is not relevant to the error I'm receiving.
After some extra digging, I came across this post in another forum.
Here, the author simply explains that what I'm trying to do doesn't work (when you would think that it should).
Because it's on another forum, I'll spell out the workaround that also worked for me (credit: jakedrew, UtterAccess post, Jun 9 2011). Basically, you need to use a client-form in addition to a client-macro as intermediate steps to get from your web form to VBA. I made this effective for my current application by doing the following:
I re-saved my function as a sub instead:
Public Sub DoTest(ByVal intArg As Integer)
MsgBox "Test sub runs smoothly with argument = " & intArg
End Sub
Create a client-form (mine is named "frmVBA_Bridge") and create the following OnOpen event:
Private Sub Form_Open(Cancel As Integer)
' run your code using this command. Note that if you don't have an argument, you won't include the part of this line following the comma
Application.Run TempVars("SubName").Value, TempVars("Arg1").Value
' reset the "parameters"
TempVars("SubName").Value = ""
TempVars("Arg1").Value = 0
DoCmd.Close acForm, Me.Name, acSaveYes
End Sub
The client-side macro "Macro1" now instead does:
OpenForm
Form Name frmVBA_Bridge
View Form
Where Condition
Data Mode
Window Mode Hidden
The web form's button's on-click embedded macro gets changed to:
If IsClient() = True Then
SetTempVar
Name SubName
Expression ="DoTest"
SetTempVar
Name Arg1
Expression = 100
RunMacro
Macro Name Macro1
End If
Quite a bit of a workaround for such a simple thing, but it seems to do the job!
Related
Question
How can i make or not make particular Tabs visible by loading a form in Access with VBA?
Explanation:
I have a Acess Database with 4 forms containing buttons. Today i started to create ribbons to get rid of those in the forms so everything is sorted and easy to overview. I want the Tabs in my Access Database to be unvisible until i open a form from my main form.
Main Form (no tabs showed) --> Switching to another form by clicking a button in my main Form (now i want to show a particular tab after opening the form)
I created my Ribbons with "Ribbon Creator 2019" for Office 2019.
Problem:
I cant solve it ... i tried so many things until i found a excel worksheet having a function by swithing sheets to display particular tabs. Its exactly what i want but i can't get it to work for my access.
By getting the name of the active form i cant get it to work and in my opinion this would be tha fastest way.
My approach:
I set "StartFromScratch" in my XML to 'true' and gave my tabs names like this: "CustomTagValue1:=xstart".
Code for my tabs (Module):
Sub GetVisible(control As IRibbonControl, ByRef visible)
' Callbackname in XML File "getVisible"
' To set the property "visible" to a Ribbon Control
' For further information see: http://www.accessribbon.de/en/index.php?Downloads:12
' Setzen der Visible Eigenschaft eines Ribbon Controls
' Weitere Informationen: http://www.accessribbon.de/index.php?Downloads:12
Select Case control.ID
Case "tab_3"
' Tab: tab_3
visible = False
Case "tab0"
' Tab: tab0
visible = False
Case "tab1"
' Tab: tab1
visible = False
Case Else
visible = True
End Select
End Sub
Code from another Module to declare my tabs:
Option Compare Database
Option Explicit
'**************************************************************************
' About this Code:
'
' This Code checks if a Formular is in active use by his 'Name'. Simple.
'**************************************************************************
Dim MyTag As String
'Callback for customUI.onLoad
Sub RibbonOnLoad(ribbon As IRibbonUI)
Set Rib = ribbon
End Sub
Sub GetVisible(control As IRibbonControl, ByRef visible)
If control.Tag Like MyTag Then
visible = True
Else
visible = False
End If
End Sub
Sub RefreshRibbon(Tag As String)
MyTag = Tag
If Rib Is Nothing Then
MsgBox "Fehler RBC1018, bitte starten Sie das Programm neu."
Else
Rib.Invalidate
End If
End Sub
Code in the Form onLoad:
Private Sub Form_Load(ByVal Sh As Object)
Select Case Screen.ActiveForm
Case "frmVerteiler": Call RefreshRibbon(Tag:="xverteiler")
Case Else: Call RefreshRibbon(Tag:="")
End Select
End Sub
Help:
I want it to work as in this excel Dokument: https://www.rondebruin.nl/win/s2/win012.htm
It is far less work and significant more easy to just create a custom ribbon for each form, and that way you don't have to write all kinds of code to hide show tabs on the ribbion. So just specify the correct ribbon for the given form, and no code is required.
I also suggest that you do NOT use call backs in the ribbon. If you adopt this approach, then the ribbon can directly call your EXISTING button code. So the code, buttons you now have can be transferred to the ribbon for that form, and you don't have to setup ribbon call backs, and all of your existing button code can remain "as is" and be called directly from the ribbon - and the ribbon will run the button code that is and remains in the form.
All you need to do is to declare any function you want called as a public function.
You then set the on action as follows:
=MyPublicFunctionName()
Note CAREFULL how we have = and () (you must have these), and they must be under the quotes.
Eg for the xml we have:
onAction="=MyDelete()"
Note how the above is DIFFERENT then a call back for a ribbon (and callbacks use sub, where this is a function). Even better is the above means you do NOT have to place the code in a standard code module, but can place the function it in the current form. So, no macro needed, no callback, and the code can go in the current form (just like it does for a command button). And bottoms to dollar, in 9 out of 10 cases, the code you need for particular form and button belongs in that particular forms code module anyway. In fact it's a very bad programming practice to start taking code that belongs in a form and placing that code in a standard public code module. The reason is for many, but all kinds of issues can crop up if you have multiple instances of that same form which is allowed in access. Furthermore when copying forms between applications, or even making a copy of the form within the same application means that you have outside code dependencies that we normally as access developers do not expect (we assume for the most part is that the code we're using for the form belongs in the forms code module and I 100% agree). I am open to the idea that this does go against the well known concept of moving UI and code apart but this is "HOW" access works. So the access way does go against trends in our industry.
Keep in mind the above function call idea is the same format we can and would have been using since near day one with menu bars in previous editions of access. So, if you are wanting to change menu bar code to ribbon, use the above idea. Also, if you have several buttons that runs code in a given form, then again the above syntax allows one to KEEP the code in the current form and simply declare the button code as a public function (you can thus real easy move buttons from a form to a ribbon if you do this).
If the function name you specified in the menu or ribbon was named as public in the form's code module, then the CURRENT FORM with the CURRENT FOCUS is where the function will be first looked for to execute. This is SIGNIFICANTLY important because it means you can use one custom menu bar for five different forms, but each of the five different forms will run a custom delete routine for example (no messing with screen.Activeform). And, you don't have to use a bunch of messy case statements as you do with a call back. In fact, all of the code stays in the form where it likely was or belongs in the first place, and that is in the forms code module.
So, if you have specific and specialized delete code that might be required for the given form that has the focus, then that's forms function code in the forms module will be run when it is called from the on action in the menu bar, or now ribbon.
This means if you set the on action to =MyDelete()
Then in each form you have, you simply declare a public functions such as
CODE
Public function MyDelete()
Code here to delete the record
End function
However it turns out for probably more then half or even close to 90% of your forms, it's entirely possible that you want a general catchall delete routine that works for all forms that don't need specialized custom deleting code. In this case you simply place the function in a standard code module (and again as public). If the current form does not have that function, then it is run from a standard code module (again, ideal behavior, and again this is how the onAction worked before ribbon).
Also, note that you also pass values directly from the ribbon.
So, ribbon xml might be:
CODE
<button id="MyDelete" label="Delete Record"
imageMso="Delete" size="large"
onAction="=MyDelete('Staff','tblStaff')"
supertip="Delete this record"
/>
In the above, I passed the table name, and a prompt text of Staff.
And the public catch all function in a standard code module will be:
CODE
Public Function MyDelete(strPrompt As String, strTable As String)
Dim strSql As String
Dim f As Form
Set f = Screen.ActiveForm
If MsgBox("Delete this " & strPrompt & " record?", _
vbQuestion + vbYesNoCancel, "Delete?") = vbYes Then
etc....
Note again how I passed two parameters to the delete routine (the text must be under single quotes). The prompt part so the msgbox command will say "Delete this staff ?". And, then I also pass the table name. What the above means is that for ten forms, if you don't specify a public function inside of the form, when the menu button is clicked on is selected, the catchall general routine in an standard code module (non forms code module) will run.
And for the few forms that have specialize deleting code, the function inside of the forms code module will run. That code might look like:
CODE
Public Function MyDelete(s1 as string, s2 as string)
' check for history
....
lngHistory = Nz(DLookup("ContactId", "NHistory", "ContactID = " & Me.ContactID), 0)
If lngHistory > 0 Then
Beep
MsgBox "You cannot delete a person with past history bookings!" & vbCrLf & vbCrLf & _
"You should simply check the 'Do NOT INCLUDE in mailings' to remove from" & vbCrLf & _
" future mailings.", vbExclamation, "Rides"
Exit Sub
End If
...code here with sql to delete record....
So a few things:
I would just create a ribbon for the given form (take your xml for the given tab, and create a whole new ribbon). Now, if you have 2 or 5 forms open, then the ribbon will automatic flip and change for you. If you try and use tabs, then a simple change of focus to another form will require you to hide+show given tabs - it becomes a real mess rather quick.
So I am trying to create a login form for a database application and I used this article as my guide.
http://accesshosting.com/create-login-form-ms-access
I followed the steps to the best of my knowledge. However, in creating the vba code for the on click procedure for the "Ok" button for the login form. using the code in the webpage I receive an error on the Private Sub Load_Form part of the codeblock. Other users seemed to have issues with this part as well.
The code in which the error is thrown is:
Private Sub Form_Load()
Me.txtUserName.SetFocus
End Sub
.SetFocus is highlighted in this case and error message is shown below.
method or data member not found
I tried researching this question and I saw that there might be an issue with naming of the controls. However, the names all matched up. When i typed Me.txtUsername it popped up with intellisense. However the .setFocus didn't appear as I was typing it.
Not sure what's up. The datatypes for each field are as follows.
userName: text, userLogin: text, userID:number, password: text
Short Version: the form cant load and its because .setFocus isn't accepted as a method. Why?
I have a Word which is used for form filling. The users are filling what is asked and some macros runs depending on what they chose or where they click. This works fine.
I recently decided to make a newer version which countains some ComboBox that are filled when the document is opened. To do that, I used the Document_Open() event.
Now here is the part I don't get : On my side, every time I do open the document, the event is triggered and the ComboBox that should get filled are filled. The problem is, so far I asked some people to test it on their own computer with their Word. Both of them came back to me saying that the ComboBox weren't filled when the document was openned.
To be more specific let's go in the code itself :
In ThisDocument, I have multiple subs that works perfectly fine and this Document_Open() event which gives me trouble.
Private Sub Document_Open()
Application.Run ("Fill.ComboBox")
End Sub
Here, Fill is the name of the Module which contains :
Sub ComboBox()
'Calling another Sub in this Module which adds the Items in the ComboBoxes
'from what parameters it is given
End Sub
Now that this has been stated, why would it work on my side but not work when another user tries it from their computer ?
Miscorsoft Word Versions :
I myself use Microsoft Office Profesionnal 2013 and so are the two users that tested it. That being said, this is intended to be working on any Word liscense from 2007 up to the current versions.
You can try in a module in your document:
Public Sub AutoOpen()
ComboBox
End Sub
I just used this in a Word 2016 document to automagically run a macro.
For documentation: https://support.microsoft.com/en-us/help/286310/description-of-behaviors-of-autoexec-and-autoopen-macros-in-word
I created my own Outlook form to use it as standard surface to enter certain orders instead of the normal message form. The creation, editing and sending works perfectly fine and in the next step I want to insert some code via VBA.
My problem is that I can´t access the objects of my form in the VBA editor. E.g. I want to show a message box when a certain checkbox is checked. According code would be:
Sub example()
If CheckBox1.Value = True Then
MsgBox("Checkbox 1 is checked.")
End If
End Sub
When I run the code I get the error that the object could not be found. The same goes for every other object, like textboxes or labels etc.
I guess the solution is pretty simple, like putting Item. or sth. like that in front of each object. But so far I wasn't able to find the solution.
I´m using Outlook 2010.
I know this is a year too late but you'll want to do something like this example below. It's kinda a work around but you can get whatever value was selected.
Sub ComboBox1_Click()
Set objPage = Item.GetInspector.ModifiedFormPages("Message")
Set Control = objPage.Controls("ComboBox1")
MsgBox "The value in the " & Control.Name & _
"control has changed to " & Control.Value & "."
End Sub
You should be able to get the value, just get a handle on the object you want using the Inspector
The following is an excerpt from here
When you use a custom form, Outlook only supports the Click event for
controls. This is a natural choice for buttons but not optimal for
controls like the combo box. You write the code by inserting it into a
form’s VBScript editor. You need to have the Outlook form open in the
Form Designer and click the View Code button found in the Form group
of the Developer tab.
Sub CheckBox1_Click()
msgbox "Hello World"
End Sub
The code page is fairly minimal with no syntax highlighting. I just tried this now and it does work. Dont forget to Publish your form to pick up the new changes.
I know this is almost 6 years late but, in VB and VBA, simply start with the form name. (And if that doesn't work, just keep going up a parent object and you'll get there.) So, your code becomes:
Sub example()
If MYFORMNAME.CheckBox1.Value = True Then
MsgBox("Checkbox 1 is checked.")
End If
End Sub
Of course, after typing "MYFORMNAME." you'll know if it will work because typomatic will kick in when the system recognizes "MYFORMNAME" after you hit the period.
I have a VBA (Excel 2010) system which involves selecting an item from a listbox and then displaying it in another form. Here is a very simplified version of what happens.
' Part of frmForm1 code module
sub lstListbox_Click
dim MyEvent as string
dim i as integer
i=me.lstListbox.listindex
MyEvent=me.lstlistbox.list(i)
' Now show the item in the second form
Load frmForm2
me.hide
ThisWorkbook.LoadDataIntoForm2 (frmForm2, MyEvent)
frmForm2.show
unload frmForm2
me.show
end sub
The listbox accepts the click, and first the event (the event handler is giver above). Key parts of the event handler are:
Load the second form (to display the detail data)
Pass the second form as a UserForm parameter to a procedure (LoadDataIntoForm2)
Hide the host form (frmForm1) and show the second form (frmForm2)
When the second form processes an Exit click, the code looks like this:
' Part of frmForm2 code module
sub cmdExit_Click
me.hide
end sub
The first time round it works fine - but when I return to frmForm1 (in the tail end of the lstListBox_Click procedure), even though the rest of the form is operative, the listbox remains stubbornly unresponsive.
I've managed to abstract this down to a little demo system if that would help - the same behavior is seen there. (It's regular .xls file, but that seems not to be easily acceptable as an upload)
Has anyone seen this before? And does anyone have any ideas how I might get this to work the way I want it to?
Thanks,
Tony
The default for the .Show method is to make the form modal. Explicitly set it to modeless:
Sub lstListbox_Click
...
Me.Show vbModeless
End Sub