I'm building a form in a Word .docm (macro enabled Word 2013 doc) with the aim of programming an Access database to import data from completed forms. I've placed textBox and comboBox controls to receive user input, but I can't get the data back out.
The examples I've seen use the Document.FormFields collection like so (in Word):
Dim fld as FormField
for each fld in ActiveDocument.FormFields
Debug.Print fld.Name & " - " & fld.Result.Text
next
However in my doc Document.FormFields is empty, but Document.Fields has 19 elements, which happens to be the number of controls in my form. That's great, except that I can't seem to get the name or value of any of the controls using a Field object. Field.Result.Text is always blank, and there is no Field.Name attribute.
So what's the difference between Field objects and FormField objects, and why are my controls showing up in Fields when all the examples I've seen use FormFields?
Am I using the wrong form controls? There are three types (I hope I'm not the only one who thinks this is ridiculous) legacy controls, ActiveX controls, and content controls. I'm using the ActiveX type.
A few things...
In MS Word terms, a 'field' doesn't have to be a form field. E.g., an auto-updated date, linked graphic, page number, etc., are all types of 'field' (or at least, were until the most recent versions of Word).
For compatibility reasons, it can be better to avoid the ActiveX controls. E.g., the Mac version of Word doesn't support them.
For best compatibility I would personally stick to the traditional form controls. Instances are named according to their bookmark name, which is settable by right clicking the control and selecting Properties. In VBA, their data is then got via the FormFields collection; if you want the value for a specific field, use
Value = ActiveDocument.FormFields("MyFieldName").Result
If all you want is to use the current fields you have, you can get the value or name from the OLEFormat.Object:
Application.ActiveDocument.Fields.Item(1).OLEFormat.Object.Value
Or
Application.ActiveDocument.Fields.Item(1).OLEFormat.Object.Name
However, I would agree with Chris in recommending that you avoid the ActiveX controls. As Microsoft says, there are a lot of reasons that they aren't the best choice for Word forms, except in very specific cases.
Using the "legacy" formfields and
//key
Application.ActiveDocument.FormFields(1).Range.Fields(1).Code
//value
Application.ActiveDocument.FormFields(1).Result
Is the solution I came up with.
I've seen companies use the bookmarks, default values, status / help texts for different purposes as well. Not that I would recommend it, but maybe they are working around an issue I'm not aware of.
I feel like .range is a bit of a hack, but considering it's the range of only the form field, unless form fields or fields can have nested fields, it should be ok.
Related
I wanted to ask whether or not MS Access can handle an attribute tagging form. Note, "attribute tagging form" was a term I innovated to describe what I had in mind. If you would happen to know the correct term, please let me know.
My Current Method:
On left pane, I have the PDF file in question with file preview. On the right, a Microsoft excel file with the title, file name and other attributes.
The task:
In the left, same PDF. On the right, I need to scroll to the right some distance to mark "Peanuts" and "Soybeans" with "1". Flagging the PDF pertinent to peanuts and soybeans.
The Question:
What I would like to do is create a form in access that would allow me to type out one of the attributes instead of having to scroll back and forth and marking it with a 1. The risk for an error would be too great once there are several dozens attributes to flag.
What I had in mind would be much like stackoverflow's tag function:
Where I can start typing an attribute, and if there is already one existing, it will autocomplete and I can move onto the next one. This will then reflect onto a database (or spreadsheet) with a 1 in the correct column and row.
Side note:
I've done some research on my own into Access' tagging function, but it would appear that it would not work to what I have in mind.
[Resource 1][4]
[Resource 2][5]
[Resource 3][6]
[Resource 4][7]
I think the term you're looking for is "search as you type". You'll find examples here on SO and elsewhere.
Basically, a text box or combobox has a On Dirty event procedure that narrows down a result list as you type the first (or any matching) letters.
In your case, once you've selected a tag, you'd add it to a list, clear the text box, so you can continue with the next tag.
I have a subform which makes a lot of use of conditional formatting to grey-out cells which cannot contain data, and highlight cells which have been adjusted by the user. The subform is a Datasheet.
This all works fine, except for the lag in applying the formatting, which sometimes even won't update until the user mouses over the cells.
What I would like to try is applying the formatting in VBA, rather than using the in-built conditional formatting, as I would rather the form takes a couple of seconds longer to load but with all formatting applied once it does, than to have the delay I'm currently getting.
So what I'm stuck on, is how to tie back a control on the subform to a specific record in the view that's populating it. For example, I can use the following code:
Dim ctrl As Control
For Each ctrl In Me.Controls
MsgBox ctrl.Name & " : " & ctrl.Value
Next ctrl
Which might display, for instance, "RowNumber : 010", so I could identify what record that control relates to, but when it says "TotalUSD : 1,234,567.89", I would have no way of knowing which record that related to, and therefore whether or not formatting should be applied.
Is there a better way of doing this, I guess ideally by being able to link each ctrl to its corresponding record in the Form.Recordset?
UPDATE
Below screenshot shows the conditional formatting as it is currently implemented, and what I am trying to achieve using VBA instead of conditional formatting.
I do not have in depth information about your implementation so here is a general suggestion that I have used in my implementations.
You should add some kind of distinguishing column to your table. For example I once had a form that showed projects and employees. The distinguishing column contained a boolean value "True" for each project, "False" for each employee. Based on that information I was able to format accordingly.
My suggestion: Add an integer distinguishing column to your recordset table. The value "0" would be a plain column, "1" would be for greyed out, "2" for user input.
In the Form_Load Event you would have to iterate through all your controls and set the formatting.
Does microsft office access have this function when i select the row from the subform,
the selected data from EmpName, ComputerName & ProductName will automatically fill into my 2 textbox at the top right and the product Name will be another combobox to select product.
Another thing is, Is it possible to do CRUD upon selection in subform?
what kind of tag should i goggle for to answer my question? I tried a lot of different tags aldy but none answers my question.
The short answer is yes. ;) You can do all those things. I well remember the day I realized that I could do anything in MS Access. (now be kind this was the first experience I had in programming)
You can reference Parent controls from subforms with this convention Me.Parent.control
For example if the Parent form has a text box named txtEmployeeId then on the Click event of a text box in the sub form you could have this code.
Me.Parent.txtEmployeeID = Me.txtEmployeeID
You can quickly extend this code to do whatever you need ie.
Me.Parent.txtComputerName = Me.ComputerName
Me.Parent.cboProductName = Me.ProductName
CRUD is a statement used in web development which seems to be where you are coming from. Access is CRUD in many ways (unless you start getting complicated) In the example above, once you navigate off the parent record with the record selector or close the form, the record is saved without any code being written. Once you start playing around with unbound controls then it becomes necessary to write code to save your work.
I want to hide or show a column based on variable data from a users selection. How do you set a column to hidden in MS-Access 2003?
For Example,
After user change event...
For Each ctl In Me.FormNameHere.Form.Controls
If (TypeName(ctl) = "Textbox") Then
If InStr(GetTextList(), ctl.Name) > 0 Then
ctl.hidden = True
Else
ctl.hidden = False
End If
End If
Next ctl
What is the best approach to this type of challenge?
Is there a more obvious solution?
Controls do not have a "hidden" property (no objects in Access have a hidden property). They do have a .Visible property.
For future reference, I suggest you familiarize yourself with the Object Browser in the VBE -- open the VBE and hit F2. You can then restrict your search to the individual libraries used in your project. It does take a while to get to the point where you understand the object model, though.
Also, you can rely on Intellisense to learn the properties/methods of an object, so in the code of the form you're working with, you can type "Me.MyTextBox." and the Intellisense dropdown will show you all the properties and methods of that particular control. It doesn't work for a generic control variable (as in your code) because different control types have different properties.
And, of course, the properties sheet gives the names of the properties, even though in code they don't always use the same orthography (usually they are the same with spaces removed).
Also, there are differences in how you might want to do this depending on whether it's a regular form or a datasheet form. In a datasheet, your controls also have .ColumnHidden and .ColumnWidth properties (setting those in any view other than datasheet view has no effect, and neither of those properties are available in the standard property sheet, but changes to them are retained when you save the form).
I answered a similar question to this not long ago to do with hiding columns on a datasheet. However you seem to want to hide textboxes arranged in a column on a form, is that correct?
Iterating over all the controls in the form could be slow if you have many controls. If you really need to use textboxes like that, then you could try group the 'columns' together then hide the groups. Another approach would be to use a listbox or datasheet to represent the data, where you can alter the layout of the columns directly.
I found the ColumnHidden property does the trick.
For Each ctl In Me.FormNameHere.Form.Controls
If (TypeName(ctl) = "Textbox") Then
If InStr(GetTextList(), ctl.Name) > 0 Then
ctl.Columnhidden = True
Else
ctl.Columnhidden = False
End If
End If
Next ctl
I got a hint from this related question.
A one-liner approach is using:
forms(fname).Controls(ctrlname).columnhidden = false
where
fname is name of your form
ctrlname is name of your control
For instance, I have a query which takes as a parameter the text property of a drop-down box [DDB1] of Form1.
How do I reference the property?
My stumbling around google has suggested that it should be something along the lines of
Forms![Form1]![DDB1].text
But I have been unable to find a definitive syntax for such references.
Any ideas?
Semi- OT - the Access2003 help, which contains links to a lot of Microsoft web pages, returns a lot of 404s when trying to load them. Is this just coincidence? Or end-of-lifing by stealth?'
To have a query reference a combo box on a form, use this syntax:
Forms!MyForm!MyComboBox
This will retrieve the selected value property of the combo box (the value of the first column, if it is a multi-column combo box).
If you want the selected value of a different column in the combo box, it is:
Forms!MyForm!MyComboBox.column(n)
Unlike most numeric indexes in VBA, n is zero based (the second column is 1).
To reference the text property, the combo box must have the focus.
The help file is apparently suffering from link rot. Here are some links in MSDN to use:
Access 2003 Programming Reference
http://msdn.microsoft.com/en-us/library/aa167788(office.11).aspx
Access 2003 Language Reference
http://msdn.microsoft.com/en-us/library/aa663079(office.11).aspx
You have in fact multiple ways to refer to a control with MS-Access. In addition to #Robert Harvey proposal, you can also write:
forms(myFormName).controls(myControlName)
Despite what #Robert says, you can access most properties of a control without setting the focus on it. One important exception is the ".text" property, which refer to the text appearing in the control, and where the focus must be set to the corresponding control.
Most of the time, the .text property is equal to the .value property, that can be accessed without setting focus on the control.
Thus, this property is useful only for controls of the combobox or listbox type, where the bound column (that gives the .value property) differs from the displayed column (giving the .text property).