Word Fields: Part I
This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
Bon Mot
Automate Word Documents with Minimal Code
By Cindy Meister
I think there is general agreement: The less code
required to update information in a Word document, the better. Some
80-plus fields are built into Word that provide information about the file
and the user; store, display, and manipulate reference information; and
link the document to other applications - all without a bit of code. This
series of articles will explore some interesting solutions that can be
accomplished with fields, field combinations, and a small amount of code
to improve user friendliness. Most of the field examples can be applied to
all versions of Word, but the code samples are VBA and therefore
applicable only to Word 97 or Word 2000.
A complete listing of available fields can be found in
the Insert | Field dialog box (see FIGURE 1). A short description of the
field's purpose is displayed there, but more in-depth information can be
referenced by first clicking the ? at the top right, then the field name,
in order to call up Help for that field. The Word Help files for fields
contain detailed information and examples, plus links to related topics
(unlike the Help for most other subjects).
FIGURE 1: The main Insert | Field dialog box.
The results of many fields can be altered or enhanced by
using switches. The user can select from a list of relevant switches by
clicking the Options button on the Insert | Field dialog box to open the
dialog box shown in FIGURE 2. FIGURE 3 lists important switches common to
many fields.
FIGURE 2: There are general, numeric, and field-specific
switches that can be added to many fields to modify or enhance their
behavior.
| Switch | Description | Example |
| \# | Numeric picture. | { MergeField Amount \# "0.00"
}
|
| \@ | Date picture. | { CreateDate \@ "MMMM d, yyyy"
}
|
| \* CharFormat | Format entire field with formatting of first field
character. | { REF Title \* CharFormat
}
|
| \* Upper \* Lower \* Caps \* FirstCap | Display field result in all upper case; all lower
case; "title" case; "sentence" case. | { MergeField LastName \* UPPER
}
|
| \! | Prevent any fields included in referenced text
from updating. | { IncludeText "C:\Large
Docs\Doc1.doc" BkmarkLastPage \* CharFormat \! }
|
| \* alphabetic | Displays alphabetic, rather then numeric
character. | { SEQ Lev2 \* ALPHABETIC } displays A
instead of 1
|
| \* Arabic |
Forces display of an Arabic number. |
|
|
\* Roman | Displays Roman numerals. |
|
|
\* Ordinal | Result is displayed as an ordinal number. | { Date \@ "d" \* Ordinal } displays
10th
|
| \* Hex | Displays the hexadecimal value. | { = 20 \* Hex } displays
14
|
| \* CardText | The number is displayed in words (no decimals).
| { Ref SUM \* CardText } displays
thirty-three
|
| \* DollarText | Number in words with two decimal places. | { = 25 + 4.15 \* DollarText} displays
twenty-nine and 15/100
|
| \* OrdText | Ordinal number as text. | { DATE \@ "d" \* OrdText \* FirstCap
} displays "Twenty-first".
|
FIGURE 3: Important, common switches.
Insert | Field is a handy tool for the average user, and
for getting an overview of available fields. It's less useful, however,
for accessing the full potential of fields in combination. Sometimes,
you'll need to work with the field codes in the document directly. FIGURE
4 lists the keyboard shortcuts and basic VBA syntax of the most important
commands.
| Action | Keystroke | VBA syntax |
| Update fields in current selection. | [F9] | Object.Fields.Update |
| Insert field brackets. | [Ctrl][F9] | Object.Fields.Add
Range:=RangeObject |
| Toggle field code display. | [Alt][F9] | View.ShowFieldCodes = True/False |
| Turn field code into plain text. | [Ctrl][Shift][F9] | Object.Fields.Unlink |
| Lock field to prevent updating. | [Ctrl][F11] | Object.Fields.Locked = True |
| Unlock field. | [Ctrl][Shift][F11] | Object.Fields.Locked =
False |
FIGURE 4: Commands for editing fields directly in a
document.
Now let's look at some of the things Word fields allow
you to do.
Referencing Information
A common task is to refer to information found in the
same or another document. Using bookmarks and REF fields, existing content
can be displayed in other areas of a document, rather than duplicating the
text. If the content of the bookmark is edited, those changes will
automatically be displayed once the REF fields are updated. REF fields are
also used by Word when generating cross-references.
Less well-known are the PAGEREF and STYLEREF fields. The
PAGEREF field returns the page number of the bookmark. When Word generates
a Table of Contents (TOC), for example, it sets bookmarks and uses hidden
PAGEREF fields to display the page numbers in the TOC. It's also the basis
of a work-around for the unreliable behavior of the two fields that
display the total number of pages in a document and in a section (NUMPAGES
and SECTIONPAGES, respectively). Simply insert a bookmark at the end of
the document or section, then put a PAGEREF field referencing that
bookmark where the total number of pages should be displayed:
{ PAGE } of { PAGEREF BookmarkName \*
CharFormat}
Note that the \* CharFormat switch will force the field
to display with the same formatting as applied to the first character in
the field, rather than that of the bookmarked text. This is important,
since the font attributes of the header or footer often differ from that
of the text.
The STYLEREF field enables you to pick up the text or
paragraph numbering from document content formatted with the specified
style. It's most frequently used in document headers or footers to display
the chapter or heading to which the current page belongs, or for
dictionary-style headers that list the first and last entry in the style
found on the page.
An interesting, less usual, application is to display
version or title information from the title page throughout a long,
multi-section document. Unlike a REF field, which depends on the presence
of bookmarks (which are prone to accidental deletion) or DocProperty
fields (that may be overlooked when updating a document), using a unique
style to mark the information meant for a STYLEREF field to pick it up is
transparent and easy for the user. To ensure that the information is
included in a document, the developer must only check for the presence of
the style on the title page, and that it contains a minimum number of
characters.
The procedure in FIGURE 5 is a possible approach. The
style name and range in which the style should be are passed to the
function. The range is checked for the presence of the style using the
Find property. If it's found, the number of characters in the range
(which now comprises what was found) is returned. Otherwise it is zero.
Error trapping is turned off for the function, because a VBA error is
returned if the style isn't found in the document's collection of styles.
Function
ExistsStyle(rng As Word.Range, _
sStyleName
As String)
As Long
On
Error Resume
Next
With rng.Find
.ClearFormatting
.ClearAllFuzzyOptions
.Forward =
True
.Wrap =
wdFindStop
.Text = ""
.Style =
sStyleName
If .Execute = True
Then
ExistsStyle = Len(rng.Text)
Else
ExistsStyle = 0
End If
End With
End
Function
FIGURE 5: Ascertain whether any text in a range is
formatted with a specific style.
Long Document Management
By now it's common knowledge that Word's Master Document
feature is buggy. Therefore, creating one long document is usually
preferable to using the feature. If, however, a set of documents should be
centrally maintained and combined as required, there are alternate
approaches. RD fields, for instance, can be used to pick up information
from other documents when generating tables of content and indexes.
Content from other Word documents is often best accessed
using the Insert | File command (see FIGURE 6). If the Link option is
activated, Word generates an INCLUDETEXT field; specifying a bookmark
range in addition brings in only that part of the file contained in the
bookmark. Normally, information is only displayed in a field. It can't be
edited on a permanent basis, and will be lost when the field is updated.
INCLUDETEXT is an exception; editing changes can be sent back to the
source document by pressing [Ctrl][Shift][F7].
FIGURE 6: The Insert | Fielddialog box in Word
2000. Click the Range button to specify a bookmark name; click the
arrow to the right of the Insert button to select the Insert
as Link option.
By combining INCLUDETEXT with IF fields, text can be
displayed according to set criteria - often a requirement for mail merge.
The following field set references a bookmark containing a dunning notice,
based on the reminder number:
{ INCLUDETEXT "C:\\My
Documents\\DunningText.doc"
{ IF {MERGEFIELD ReminderNum }
= 1 "Notice1"
"{IF { MERGEFIELD ReminderNum }
= 2 "Notice2"
"Notice3" }" } }
Note that Word's IF field doesn't use argument
separators; each True/False pair is marked by a pair of quotation marks
separated by a space.
INCLUDETEXT can also be used to generate consecutive
page numbering across multiple documents. In the first document of a pair:
- Insert a PAGE field at the end of the document.
- Select it and assign it a bookmark (PageNum, for example).
- Format it as hidden or white so it won't be visible.
In the second document of the pair:
- Create an expression field that adds the current page number in this
document to the page number in the first document, referenced using an
INCLUDETEXT field.
- Complete the INCLUDETEXT field with a \* CharFormat and a \* !
switch to override the hidden formatting, and prevent the PAGE field
being referenced to update to the page number in the current document.
For example:
{ = { PAGE } + { INCLUDETEXT
"C:\\My Documents\\Chap1.doc"
PageNum \* CharFormat \* ! }
}
Linked Excel Tables and Charts
Reports often include tables or charts that were created
with Excel. The question of the best/easiest way to insert this
information in Word often comes up. On the whole, copying the Excel data
and using Paste Special to insert it in a Word document gives the best
results. It allows you to control the selection exactly. You can choose to
insert a table as an object, or in Word table format, and you can specify
whether to set up a link.
Of course, this approach is less satisfactory if the
reporting tool should be fully automated. But an examination of the Paste
Special result indicates an alternate solution. Paste Special with a link
inserts a LINK field, such as:
{ LINK Excel.Sheet.8
"C:\\My Documents\\Monthly
Reports\\JAN2000.XLS"
NorthRegionSales!R1C1:R11C6 \a
\r \* MERGEFORMAT }
Or, for a chart:
{ LINK Excel.Chart.8
"C:\\My Documents\\Monthly
Reports\\JAN2000.XLS"
"All Regions Sales Chart" \a \p
}
All that's needed to generate this field in VBA are the
various elements in the field: the application class, the file path, and
the workbook range. The optional \a switch instructs Word to automatically
update the link. The switches \p and \r determine how the table
information should be displayed - as a picture (OLE object), or in
RichText format (as a Word table), respectively.
Include the \* MergeFormat switch when formatting
applied directly in Word should override Excel formatting when the field
is updated. (Please note this is broken in Word 2000.) A very simple
example is demonstrated in FIGURE 7. All the field elements are
determined, then combined into sFieldText. For the Add
method of the Fields object, the Range (end of the document)
is required. The Type of field is passed as a built-in Word
constant; the Text will automatically follow the field name.
PreserveFormatting instructs VBA whether to include the \*
MergeFormat switch.
Sub
InsertLinkFieldForExcelData()
Dim rng As Word.Range
Dim sWBPath As
String
Dim sSheet As
String
Dim sRange As
String
Dim sAppClass As
String
Dim sFieldText As
String
' Field
will be inserted at the end of current document.
Set rng = ActiveDocument.Range
rng.Collapse
Direction:=wdCollapseEnd
' Info
required for creating LINK field.
sWBPath = _
"C:\\My
Documents\\Monthly Reports\\JAN2000.XLS"
sSheet = "NorthRegionSales"
sRange = "SalesData"
If
Instr(sSheet, "Chart") = 0 Then
sAppClass =
"Excel.Sheet.8"
sFieldText =
sAppClass & " " & """" & sWBPath & _
""""
& " " & """" & sSheet & "!" & _
sRange & """" & " \r"
Else
sAppClass =
"Excel.Chart.8"
sFieldText =
sAppClass & " " & """" & sWBPath & _
""""
& " " & """" & sSheet & """" & " \p"
End If
' Insert
the LINK field.
ActiveDocument.Fields.Add
Range:=rng, _
Type:=wdFieldLink, Text:=sFieldText, _
PreserveFormatting:=
True
' Break
the link to the Excel source.
rng.MoveEnd wdCharacter,
1
rng.Fields.Unlink
End
Sub
FIGURE 7: Include the \* MergeFormat switch when
formatting applied directly in Word should override Excel formatting when
the field is updated.
Sometimes the Excel data should not remain linked to its
source. In this case, the field can simply be unlinked after it's been
inserted, resulting in an embedded object, or - if a spreadsheet has been
inserted in RichText format - a Word table.
Take Control of Numbering
There are definite problems maintaining auto-numbering
when converting between Word 97/2000 and earlier versions, as well as with
numbering in shared or exchanged Word 97/2000 documents. SEQ fields
provide an alternative that's stable and reliable across all versions of
WinWord. SEQ is short for "sequence" and enables you to have many
independent lists in a document. Word itself uses SEQ fields to generate
figure numbering sequences in captions.
The basic SEQ field is quite simple. It consists of the
field name plus the sequence identifier, e.g. { SEQ HdLevel1 }. The
field-specific switches, shown in FIGURE 8, provide versatility and
flexibility when generating sequences.
| \c | Repeats the closest preceding sequence number.
This is useful for inserting chapter numbers in headers or footers.
|
| \h | Hides the field result. Use it to refer to a SEQ
field in a cross-reference without printing the number. For example,
you might want to refer to a numbered chapter, but not print the
chapter number. The \h switch doesn't hide the field result if a
Format (\*) switch is also present. |
| \n | Inserts the next sequence number for the specified
items. This is the default. |
| \r n | Resets the sequence number to the specified number
n. For example, { SEQ figure \r 3 } starts figure numbering
at 3. |
| \s | Resets the sequence number at the heading level
following the "s". For example, { SEQ figure \s 2 } starts numbering
at the Heading 2 style (not available in older versions of Word.)
|
FIGURE 8: SEQ field switches (from Word's Help files).
For example, a three-level, outline-numbering sequence
can be created using the combinations shown in FIGURE 9. If each
outline-level field combination is saved as an individual AutoText entry,
the numbering can quickly be inserted by the user from keyboard
assignments, or a toolbar with buttons for each outline level, or an
AutoText list.
| Result | SEQ Field |
I.
| { SEQ HdLevel1 \* ROMAN
}.
|
I.A.
| { SEQ HdLevel1 \c \* ROMAN }.{ SEQ
HdLevel2 \* ALPHABETIC }.
|
I.A.1.
| { SEQ HdLevel1 \c \* ROMAN }.{ SEQ
HdLevel2 \c \* ALPHABETIC }.{ SEQ HdLevel3 }.
|
I.A.2.
| { SEQ HdLevel1 \c \* ROMAN }.{ SEQ
HdLevel2 \c \* ALPHABETIC }.{ SEQ HdLevel3 }.
|
II.
| { SEQ HdLevel1 \* ROMAN
}
|
II.B.
| { SEQ HdLevel1 \c \* ROMAN }.{ SEQ
HdLevel2 \* ALPHABETIC }
|
FIGURE 9: Outline numbering using SEQ fields.
One drawback of using SEQ fields is certainly the fact
that the numbering will not update automatically when the order of
numbered items is changed, or a new item is inserted into an existing
list. Indeed, exactly what causes fields to update (and when) can be very
confusing (Knowledge Base article Q89953 provides some explanation).
Activating Tools | Options | Print | Update Fields should ensure that
everything will be correct when the document is printed, but may not be a
satisfactory solution for the user working with the document.
Programmatically, all fields in a document can be
updated using a routine such as this:
Sub
UpdateAllDocFields()
Dimsry
ForEach sry
In ActiveDocument.StoryRanges
sry.Fields.Update
NextStr
End
Sub
If the document is large, however, or contains many
fields - especially complex field sets or fields that force repagination -
this process can be rather slow. It may therefore be advantageous to
update only certain types of fields. The following procedure demonstrates
how to update only SEQ fields of a HdLevel sequence:
Sub
UpdateOnlyHdLevelSEQFields()
Dim fld As Word.Field
For Each fld
In ActiveDocument.Fields
If fld.Type =
wdFieldSequence Then
If InStr(fld.Code, "HdLevel") <> 0
Then
fld.Update
End If
End If
Next fld
End
Sub
SEQ fields can also be used to generate types of
numbering sequences that Word's autonumbering cannot (for example,
incrementing numbering by a factor other than one, or numbering a list in
reverse order). FIGURE 10 shows the field combinations for generating a
sequence from 5 to 1. Set a starting number that's one higher than the
number you want to count down from; then subtract the value of the SEQ
sequence from that number.
{ Set StartNum 6 }
{ = { StartNum } - { SEQ RevNum1 } \#
0 } Paragraph 5
{ = { StartNum } - { SEQ RevNum1 } \#
0 } Paragraph 4
{ = { StartNum } - { SEQ RevNum1 } \#
0 } Paragraph 3
{ = { StartNum } - { SEQ RevNum1 } \#
0 } Paragraph 2
{ = { StartNum } - { SEQ RevNum1 } \#
0 } Paragraph 1
Of course, you can make it much easier for the user to
create such sequences with a bit of VBA code, such as that shown in Listing
One. The user selects the paragraphs to be numbered in reverse order,
then starts the macro. The starting (high) number is the number of
paragraphs selected plus one. Rather than using a SET field to set the
starting number, this procedure places it in a document property, which is
less likely to be deleted accidentally. It also allows for multiple
reversed numbering lists in the same document, by incrementing a number at
the end of the document property and sequence names. The field set is
generated once, then stored as an AutoText entry for creating the
remainder of the list, for two reasons:
- Inserting an AutoText entry is generally faster than recreating the
field set.
- The code works with the Range object to insert the AutoText
entry, rather than the Selection object used when creating the
fields set, making it more accurate.
You will notice that the procedure to generate the field
set, NewRevNumFieldSet, began as a recorded macro and uses the
Selection object. Microsoft neglected to provide a VBA method to
create nested fields. It isn't possible to include the field bracket
characters as part of a string; they must be inserted separately. There
are a number of approaches to the problem of creating nested fields, none
of them particularly satisfactory from a developer standpoint. One is to
record a macro, edit it judiciously, and test it very thoroughly. An
alternate method based on the Range will be presented in the next
installment of this series.
Conclusion
Hopefully, this article has animated you to explore how
Word fields can render your documents more powerful. Part II of this
series will continue to look at teaching Word how to overcome its
limitations with the help of complex field sets.
Cindy Meister has her own consulting business,
INTER-Solutions, based in Switzerland. Prior to becoming independent, she
spent three years as a consultant/trainer for Deloitte & Touche in
Zurich. Five years experience as head of administration in an
international organization and a Bachelor of Science provide her with a
broad background for understanding customer requirements. Cindy's fully
bilingual (English and German), with customers in four countries (and
counting) and is a regular contributor to the German edition of Inside
Word. Four years as a Microsoft MVP for MSWord support and as Sysop in the
CompuServe MSWord forum have given her in-depth knowledge of Microsoft
Office and Word. For general questions on Word and links to other useful
sites, visit her Web site at http://homepage.swissonline.ch/cindymeister.
You can reach her at mailto:cindymeister@swissonline.ch.
Begin Listing One - Create
numbering sequences with VBA
' Number the selected
paragraphs in reverse order.
Sub
NumberInReverse()
Dim iStartNum As
Long
Dim sPropName As
String
Dim rngSelection As
Word.Range
Dim rngWork As Word.Range
Dim sATName As
String
Dim iCounter As
Long
Application.ScreenUpdating =
False
ActiveDocument.Windows(1).View.ShowFieldCodes =
False
' Get the
number of selected paragraphs.
iStartNum =
Selection.Paragraphs.Count
' Define a
DocProperty to hold the high number + 1.
sPropName =
CreateStartNumDocProp("StartNum", iStartNum)
' Save the
current selection in a range
' because
the selection will be changing.
Set rngSelection = Selection.Range
' Create
duplicate to work with.
Set rngWork = rngSelection.Duplicate
rngWork.Collapse
wdCollapseStart
' Create
and insert first number in sequence.
sATName =
CreateReverseOrderCounter(sPropName)
' Insert
remaining numbers at start of
' each
paragraph in selection.
For iCounter = 2 To
iStartNum
' Set working range to next paragraph.
Set rngWork =
rngSelection.Paragraphs(iCounter).Range
rngWork.Collapse
wdCollapseStart
ActiveDocument.AttachedTemplate.
_
AutoTextEntries(sATName).Insert
_
Where:=rngWork,
RichText:= True
Next
' Update
only fields in selection
'
(reverse-order numbering).
rngSelection.Fields.Update
End
Sub
' Returns DocProperty
name.
Function
CreateStartNumDocProp(ByVal sPropName,
_
ByVal PropValue As
Long) As
String
Dim prop As
Office.DocumentProperty
' If no
DocProperties, or none with StartNum in name
'
DocProperty name is StartNum1.
If
ActiveDocument.CustomDocumentProperties.Count = 0
Then
sPropName =
"StartNum1"
Else
' Otherwise, increment StartNum by 1.
For Each prop
In ActiveDocument. _
CustomDocumentProperties
If Left(prop.Name, 8) = "StartNum"
Then
sPropName =
_
"StartNum"
& CStr(Val(Mid(prop.Name, 9)) + 1)
Else
sPropName =
"StartNum1"
End If
Next prop
End If
' Create
DocProperty and set value to
' number
of selected paragraphs plus 1.
ActiveDocument.CustomDocumentProperties.Add
_
Name:=sPropName,
Type:=msoPropertyTypeString, _
Value:=
CStr(PropValue + 1), LinkToContent:=
False
CreateStartNumDocProp =
sPropName
End
Function
' Returns name of
AutoText entry that creates
' the reverse order
list.
Function
CreateReverseOrderCounter( _
ByVal sPropName As
String) As
String
Dim sRevNum As
String
Dim sATName As
String
sRevNum = Mid(sPropName, 9)
sATName = "SEQAT" &
sRevNum
' Create
the field set and insert
' first
one at beginning of selection
Selection.Collapse
wdCollapseStart
Call NewRevNumFieldSet(sPropName, "RevNum" & sRevNum)
' Create
an AutoText entry for rest of list
' because
inserting it will be faster and more accurate.
Selection.MoveRight
wdCharacter, 1, Extend:= True
ActiveDocument.AttachedTemplate.AutoTextEntries.Add
_
Name:=sATName,
Range:=Selection.Range
CreateReverseOrderCounter =
sATName
End
Function
' Recorded macro that
generates the set of nested fields
' for a sequence that
counts in reverse:
' { = {DocProperty
StartNum} - {SEQ RevNum} }
Sub
NewRevNumFieldSet(sProp, sRevNum)
'
Expression field
Selection.Fields.Add
Range:=Selection.Range, _
Type:=wdFieldEmpty, Text:="= ", _
PreserveFormatting:=
False
' Show
field codes to position IP.
ActiveWindow.View.ShowFieldCodes =
True
Selection.MoveRight
Unit:=wdCharacter, Count:=4
Selection.Fields.Add
Range:=Selection.Range, _
Type:=wdFieldEmpty, Text:="DOCPROPERTY " &
sProp, _
PreserveFormatting:=
False
Selection.TypeText Text:=" - "
Selection.Fields.Add
Range:=Selection.Range, _
Type:=wdFieldEmpty, Text:="SEQ " & sRevNum,
_
PreserveFormatting:=
False
ActiveWindow.View.ShowFieldCodes =
False
Selection.Fields.Update
End
Sub
End Listing One