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

This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.

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