简体   繁体   中英

How to fill multiple Bookmarks / FormFields in Word from the same field in Access using VBA

I had previously been using some VBA to pass fields from Access into a Word document, until coming up against the 255 character limit. Assistance from this site has led me to now use Bookmarks instead of Form Fields.

I was originally filling many different fields on Word and in some instances using the same data from Access in two places on the Word document. I was achieving this by calling:

.FormFields("txtReasonforReward").Result = Me![Reason for Reward]
.FormFields("txtReasonforReward2").Result = Me![Reason for Reward]

As I now have a different way of filling the "Reason for Reward" box, to circumvent the character limit (code below), I'm not sure how to fill "txtReasonforReward2". I do have several instances where I've added a second field and stuck a 2 on the end... I'm not convinced this is the best way so if anybody can advise on how to achieve this with both FormFields and Bookmarks, I'd be really grateful.

Dim objWord As Object
Set objWord = CreateObject("Word.Application")
objWord.Visible = True
Set doc = objWord.Documents.Open(***path to file***, , True)

Dim rng As Word.Range
Dim x As String

With doc
.FormFields("txtFirstName").Result = Me![First Name]
.FormFields("txtLastName").Result = Me![Last Name]
`examples cut for clarity...
.FormFields("txtHRID").Result = Me![ID]
.FormFields("txtPeriod").Result = Me![Period]

If doc.ProtectionType <> wdNoProtection Then
   doc.Unprotect
End If

Set rng = doc.Bookmarks("txtReasonforReward").Range
rng.MoveStart wdCharacter, -1
x = rng.Characters.First
rng.FormFields(1).Delete
rng.Text = x & Me![Reason for Reward]
doc.Protect wdAllowOnlyFormFields, True

.Visible = True
.Activate

End With

objWord.View.ReadingLayout = True

Building on the code in the question and the background question...

Word can duplicate the content of a bookmark using REF field codes. Since form fields also use bookmark identifiers, this will work with existing form fields as well as bookmarked content. REF fields can be inserted directly, if a person is familiar with doing so OR by inserting a cross-reference to the bookmark.

Referring to the work-around for inserting more than 255 characters, in this case it will be necessary to also place a bookmark around the range being inserted and to update the REF fields so that they mirror the bookmark content throughout the document. The modified section of code is below.

'Declarations to be added at the beginning of the procedure
Dim fld As Word.Field
Dim bkmName As String

'Name of form field, bookmark to be added and text in REF field code
bkmName = "txtReasonforReward"     

'Existing code
If doc.ProtectionType <> wdNoProtection Then
   doc.Unprotect
End If
Set rng = doc.Bookmarks(bkmName).Range
rng.MoveStart wdCharacter, -1
x = rng.Characters.First
rng.FormFields(1).Delete
rng.Text = x & Me![Reason for Reward]

' New code
'Leave that single character out of the range for the bookmark
rng.MoveStart wdCharacter, 1
'Bookmark the inserted content
doc.Bookmarks.Add bkmName, rng
'Update fields so that REF's pick up the bookmark content
For Each fld In doc.Fields
    If fld.Type = wdFieldRef Then
        fld.Update
    End If
Next

doc.Protect wdAllowOnlyFormFields, True

This approach will get a bit unwieldy if it needs to be applied to many fields. It might make sense to do something like write the bookmark names to a Tag property of the controls in the Access form then loop the controls to pick up bookmark name and data from the control, rather than writing each out explicitly - but this is just a thought for the future.

All that being said, the "modern" way to achieve this is to work with content controls instead of form fields/bookmarks. Content controls do not have the 255 character limit, the document can be protected as a form, multiple content controls can have the same title (name) and/or tag. Furthermore, content controls can be "mapped" to a Custom XML Part stored in the document so that changing the content of one will change the content of another. Trying to describe all that would go beyond what should be in an "answer", here, but is all publicly available by searching the Internet.

Personally, if this were my project and knowing what I know of it: If form fields are not required in the document (no user input via the fields is expected) I would use bookmarks and REF fields, only.

There are so may ways to do this kind of thing. Take a look at the approach below and see if you can get it to work.

Option Compare Database
' This concept uses Docvariables in MS Word
Sub PushToWord()

Dim wapp As Word.Application
Dim wdoc As Word.Document
Dim db As DAO.Database
Dim fld As DAO.Field
Dim rs As DAO.Recordset
Dim filenm As String
Dim NumFields As Integer
Dim i As Integer

Set db = CurrentDb
Set rs = db.OpenRecordset("tbl_CustomerData")

Set wapp = New Word.Application
wapp.Visible = True


Set rs = DBEngine(0)(0).OpenRecordset("SELECT * FROM tbl_CustomerData")

If rs.RecordCount > 0 Then
  rs.MoveFirst

  Do While Not rs.EOF
     For i = 0 To rs.Fields.Count - 1
        Set fld = rs.Fields(i)
        Debug.Print fld.Name, fld.Value
            If fld.Value = 20 Then
                filenm = "C:\Users\Ryan\Desktop\Coding\Integrating Access and Word\From Access to Word\Letter1.doc"
                    Set wdoc = wapp.Documents.Open(filenm)
                wapp.ActiveDocument.Variables("Name").Value = rs.Fields("Name").Value
            End If
     Next
     rs.MoveNext
  Loop
  Set fld = Nothing
  rs.Close
End If
Set rs = Nothing

End Sub

The code runs from Access, and you can fire it off any number of ways (button click event, form load event, some other object event, etc.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM