I am trying to write a VBA script that will read the value of a merge field in an MS Word document. This field's code is:
{MERGEFIELD Vendor_ID \* MERGEFORMAT}
I have tried accessing it via MailMergeField:
' No access by ID, must use an index:
ActiveDocument.MailMerge.Fields(1)
but this object does not seem to provide the value. I then tried to do the same via MailMergeDataField, but again in vain, because the document has no data fields, i.e.
ActiveDocument.MailMerge.DataSource.DataFields.Count = 0
At last, I endeavored to follow the example from the DataFields documentation only to find out that the data source has no records:
ActiveDocument.MailMerge.DataSource.RecordCount = -1
Now I give up and ask your help in reading the value of a merge field. Here is a sample document from which I am trying to read the value of the Vendor_ID merge field—400775. Beware that it already contains some VBA code with my failed attempts. The bookmark V_Vendor_Number comprises that value, but I have an explicit requirement not to use bookmarks.
If you have a document that doesn't present you with a mailmerge SQL prompt when you open it, it isn't a mailmerge main document and isn't connected to a data source. Accordingly, all you're left with is reading through the fields collection to find the one you're interested in. You can also take the same approach with a mailmerge main document that is connected to a data source. For example:
Sub Demo()
Dim Fld As Field
For Each Fld In ActiveDocument.Fields
With Fld
If .Type = wdFieldMergeField Then
If Trim(Split(Split(.Code.Text, "MERGEFIELD ")(1),"\")(0)) = "Vendor_ID" Then
MsgBox .Result.Text: Exit For
End If
End If
End With
Next
End Sub
Related
I'm trying to export (button click) data from Access recordset (data from 2 columns - "Question" & "Answer") to Word template which has FormFields "Question" & "Answer".
I managed to do it but only until Word document runs out of FormFields (which I added - 100), if recordset has more than 100 rows, it will result with an error "error 5941 the requested member of the collection does not exist" - because it run out of available FormFields (at this time max number of questions is 1100, and it will grow). I can, btw, add several thousand FormFields, but then user will have to delete the empty ones when he uses this option.
I feel like there is an easy way to implement some other kind of loop which will take a document which has only these two FormFields and copy or duplicate first FormField - "Question" and insert data in second, but I still didn't find any way of doing that.
Exporting data from 2 columns in Access recordset, one is "Question" and other "Answer". Code on ButtonClick:
Private Sub cmdToWordMultiple_Click()
Dim db As DAO.Database
Dim rst As DAO.Recordset
Set db = CurrentDb()
Set rst = Me.RecordsetClone
Set Wd = New Word.Application
Set myDoc = Wd.Documents.Add("C:\Users\User\Desktop\ReportQuestions.docx")
Wd.Visible = True
rst.MoveFirst
Do Until rst.EOF
myDoc.FormFields("Question").Range.Text = Nz(rst!Question, "")
myDoc.FormFields("Answer").Range.Text = Nz(rst!Answer, "")
rst.MoveNext
Loop
rst.Close
Set rst = Nothing
objWord.Application.Quit
End Sub
I would like to make this button export data from Access recordset to Word Document, without leaving excess FormFields.
Most efficient is to save the form fields as Building Blocks which can be inserted as often as required. Building Blocks can only be saved in a template, so open ReportQuestions.docx then use File/Save As to save it as a dotx.
Select the pair of form fields, then use Insert->Quick Parts->Save selection to quick part gallery. Fill out the fields in the dialog box being sure to select the template ReportQuestions.dotx for "Save in".
To insert the form fields, the code would look something like below. Note, also, how to get to the end of the document on each iteration, before inserting the next pair of form fields. (See also note below the code!)
Dim tmpl as Word.Template
Dim sTmplPath as String
sTmplPath = "C:\Users\User\Desktop\ReportQuestions.dotx"
Set myDoc = Wd.Documents.Add(sTmplPath)
Set tmpl = myDoc.AttachedTemplate
Dim rngEndOfDoc as Word.Range
Set rngEndOfDoc = myDoc.Content
rngEndOfDoc.Collapse wdWollapseEnd
tmpl.BuildingBlockEntries("Name of Entry").Insert Where:=rngEndOfDoc, RichText:=True
This builds on the code shown in the question. Based on my experience with form fields, I suspect this code, as shown, does not work for more than one pair of form fields because form field names are also Word bookmarks. And bookmark names must be unique (can only appear once) in a document. So Question and Answer can only be used once. I don't know what you're actually naming the form fields, but you'll probably need to add code to rename the form fields once they've been inserted.
Added from OP's comment: The suggestion was successfully implemented like this
Do Until rst.EOF
tmpl.BuildingBlockEntries("Answer").Insert Where:=rngEndOfDoc, RichText:=True myDoc.FormFields("Answer").Range.Text = "ANSWER: " & Nz(rst!Answer, "")
rst.MoveNext
Loop
I have an Excel file with employee data and a Word template. I have mail merged and created a macro which asks me for the employee name, and based on the name, it fetches the employee details of that employee to the Word file from the Excel file.
The macro is able to retrieve records if the record comes from top to bottom of the Excel sheet. However, any record which is above the current retrieved record is not getting fetched. It's really a trouble. Could you please help?
Below is my code:
Sub getdata()
Dim numRecord As Integer
Dim myName As String
myName = InputBox("Enter Name:")
Set dsMain = ActiveDocument.MailMerge.DataSource
If dsMain.FindRecord(FindText:=myName, Field:="Name") = True Then
numRecord = dsMain.ActiveRecord
End If
End Sub
Here is a direct quote from the MailMergeDataSource.FindRecord Method documentation:
"The FindRecord method does a forward search only. Therefore, if the active record is not the first record in the data source and the record for which you are searching is before the active record, the FindRecord method will return no results. To ensure that the entire data source is searched, set the ActiveRecord property to wdFirstRecord ."
This, according to the MailMergeDataSource.ActiveRecord Property documentation will be something like:
With ActiveDocument.MailMerge
.DataSource.ActiveRecord = wdFirstRecord
End With
I need to find a way to automatically update some procedure documents (word docs) with fields from a spreadsheet:
There are 20 documents in total, so really I would like a single method where I can apply updates to all documents in one go.
All the documents are based on the same template; however, each contians an table (which logs the version history for that document). The content of this table is unique and the number of rows varies from document to document.
The first thing I though of was using a mailmerge; however, this would mean I woudl loose the unique tables from each document and would have to re add them, which would defeate the point of automating the process.
I have made the fields that I want to update in the word doc as Legacy Text Form Fields, and have found some VBA code which enables me to specify, that specific form fields should update from specific cells in my spreadsheet; however, I have to specify these for each docment individually.
This is the code I am using
"FormFields("Field1").Result =ActiveWorkbook.Sheets("Sheet4").Range("A2").Value"
Ideally I need a method that will work for every word doc in a given folder, identifing the related row in the spreadsheet and updating the doc accordingly. The word docs are named as the Doc ID (first column in spreadsheet).
Add DocVariables in Word. If you don't know how to do this, Google it. Then, run the script below, from Excel.
Sub PushToWord()
Dim objWord As New Word.Application
Dim doc As Word.Document
Dim bkmk As Word.Bookmark
sWdFileName = Application.GetOpenFilename(, , , , False)
Set doc = objWord.Documents.Open(sWdFileName)
objWord.activedocument.variables("BrokerFirstName").Value = Range("BrokerFirstName").Value
objWord.activedocument.variables("BrokerLastName").Value = Range("BrokerLastName").Value
ActiveDocument.Fields.Update
objWord.Visible = True
End Sub
Finally, loop through all Word docs in a single folder.
We recently wrote some code for a client using the Aspose.pdf library, on my system the pdf in question opened fine and most of the merge fields were filled in (we don't have the exact list of merge fields that they do).
They're telling me that on their system, some documents take 2-4 mins to open while others don't open at all.
What could be a possible cause of the document not opening at all?
My code is below:
' Load form
Dim doc As Aspose.Pdf.Document = New Aspose.Pdf.Document(sTemplateDir & sDocName)
'Get names of form fields
Dim fields As Aspose.Pdf.InteractiveFeatures.Forms.Field() = doc.Form.Fields
Dim sField As String
Dim field As Aspose.Pdf.InteractiveFeatures.Forms.Field
If fields.Length > 0 Then
For Each field In fields
'Get name of field
sField = field.FullName
'If the merge field isn't valid then we'll just leave it and assume its a fill-in
If nMergeCol.Contains(sField) And Not IsNothing(sField) Then
field.Value = nMergeCol.Item(sField)
End If
Next
End If
This has been resolved! As we suspected, it was a problem with the client's Javascript within the pdf file. The problem was within the calculations the absolute value was being used (name.value). Once this was switched to the relative value (this.event.value) the pdf file began behaving correctly with the AsPose code.
I'm creating a word document from scratch as an OLE object via VBA, and have created cross-references in it. I am actually using LotusScript, but the principles of VBA should apply.
Once I have created the cross-reference, I format the entire table cell that contains it (Arial 8 Italic), but when the document is saved, the field updates its format. I know that I can set a property of the field manually by ticking the "Preserve formatting during updates " option in the Word front-end, but is there a VBA property for that?
NB, The cross-reference is to a heading, and the formatting I'm getting appears to be the same as that heading, which is not what I want.
Many thanks,
Phil
I found the solution :-)
This is LotusScript, but I'm sure VB users can work out what it means. Also, I call a function and 3 subroutines, which are all self-explanatory. rg is a Range, in which I've just created the cross-reference. Due to the nature off the application, I know that the field is the first one in the range. The final line is the important one.
Set rg = getTableCell(subTable, 2, 1).Range
Dim fld As Variant
Set fld = rg.Fields(1)
Call SetItalicsOnOff(rg, True)
Call SetFontFace(rg, "Arial")
Call SetFontSize(rg, 8)
fld.Code.Text = fld.Code.Text & " \* MERGEFORMAT"