none
Adding text after inserting a field with VBA RRS feed

  • Question

  • I have been trying to insert combinations of text and fields in a Word header using the Range object. If I insert the fields manually there is no problem: After the insertion the cursor is behind the field, so further elements can be added. But if I use VBA, for some fields the cursor remains in from of the field.

    The three subroutines below illustrate this problem:

    In the first texts and fields are added sequencially, but only the FileName field is positioned properly, the Date, Page and NumPage fields appear in reverse order.

    In the second sub I have updated the range object after each insertion of these fields. This works, but is not beautiful and would not work if applied in the middle of a document.

    In the third version insertions are made in reverse order. This works fine, but the code is more difficult to comprehend.

    So my questions are:

    • How can I easily get behind a newly inserted field?
    • Why do fields behave different from each other when inserted by code?

    Best wishes

    Holger Nielsen

    Denmark

     

     

     

    Sub CreateHeaderForwardsNotOk()

        Dim doc As Word.Document, rng As Word.Range

        Set doc = ActiveDocument

        Set rng = doc.Sections(1).Headers(wdHeaderFooterPrimary).Range

        With rng

            .Fields.Add Range:=rng, Type:=wdFieldFileName, PreserveFormatting:=True

    '        .Collapse wdCollapseEnd

            .InsertAfter (" ")

            .Collapse wdCollapseEnd

            .Fields.Add Range:=rng, Type:=wdFieldDate, Text:="\@ YYYY-MM-DD", PreserveFormatting:=True

            .Collapse wdCollapseEnd

            .InsertAfter (vbTab)

            .Collapse wdCollapseEnd

            .InsertAfter (":-(")

            .Collapse wdCollapseEnd

            .InsertAfter (vbTab)

            .Collapse wdCollapseEnd

            .InsertAfter ("Page ")

            .Collapse wdCollapseEnd

            .Fields.Add Range:=rng, Type:=wdFieldPage, PreserveFormatting:=True

            .Collapse wdCollapseEnd

            .InsertAfter (" of ")

            .Collapse wdCollapseEnd

            .Fields.Add Range:=rng, Type:=wdFieldNumPages, PreserveFormatting:=True

            .Collapse wdCollapseEnd

        End With

        doc.Sections(1).Headers(wdHeaderFooterPrimary).Range.Fields.Update

    End Sub

     

    Sub CreateHeaderForwardsOkButAwkward()

        Dim doc As Word.Document, rng As Word.Range

        Set doc = ActiveDocument

        Set rng = doc.Sections(1).Headers(wdHeaderFooterPrimary).Range

        With rng

            .Fields.Add Range:=rng, Type:=wdFieldFileName, PreserveFormatting:=True

    '        .Collapse wdCollapseEnd

            .InsertAfter (" ")

            .Collapse wdCollapseEnd

            .Fields.Add Range:=rng, Type:=wdFieldDate, Text:="\@ YYYY-MM-DD", PreserveFormatting:=True

        End With

        Set rng = doc.Sections(1).Headers(wdHeaderFooterPrimary).Range

        With rng

            .Collapse wdCollapseEnd

            .InsertAfter (vbTab)

            .Collapse wdCollapseEnd

            .InsertAfter (":-|")

            .Collapse wdCollapseEnd

            .InsertAfter (vbTab)

            .Collapse wdCollapseEnd

            .InsertAfter ("Page ")

            .Collapse wdCollapseEnd

            .Fields.Add Range:=rng, Type:=wdFieldPage, PreserveFormatting:=True

        End With

        Set rng = doc.Sections(1).Headers(wdHeaderFooterPrimary).Range

        With rng

            .Collapse wdCollapseEnd

            .InsertAfter (" of ")

            .Collapse wdCollapseEnd

            .Fields.Add Range:=rng, Type:=wdFieldNumPages, PreserveFormatting:=True

        End With

        Set rng = doc.Sections(1).Headers(wdHeaderFooterPrimary).Range

        With rng

            .Collapse wdCollapseEnd

        End With

        doc.Sections(1).Headers(wdHeaderFooterPrimary).Range.Fields.Update

    End Sub

     

    Sub CreateHeaderBackwards()

        Dim doc As Word.Document, rng As Word.Range

        Set doc = ActiveDocument

        Set rng = doc.Sections(1).Headers(wdHeaderFooterPrimary).Range

        With rng

            .Fields.Add Range:=rng, Type:=wdFieldNumPages, PreserveFormatting:=True

            .Collapse wdCollapseStart

            .InsertBefore (" of ")

            .Collapse wdCollapseStart

            .Fields.Add Range:=rng, Type:=wdFieldPage, PreserveFormatting:=True

            .Collapse wdCollapseStart

            .InsertBefore ("Page ")

            .Collapse wdCollapseStart

            .InsertBefore (vbTab)

            .Collapse wdCollapseStart

            .InsertBefore (":-)")

            .Collapse wdCollapseStart

            .InsertBefore (vbTab)

            .Collapse wdCollapseStart

            .Fields.Add Range:=rng, Type:=wdFieldDate, Text:="\@ YYYY-MM-DD", PreserveFormatting:=True

            .Collapse wdCollapseStart

            .InsertBefore (" ")

            .Collapse wdCollapseStart

            .Fields.Add Range:=rng, Type:=wdFieldFileName, PreserveFormatting:=True

            .Collapse wdCollapseStart

        End With

        doc.Sections(1).Headers(wdHeaderFooterPrimary).Range.Fields.Update

    End Sub

    Wednesday, May 14, 2014 1:21 PM

Answers

  • Hi Holger

    There's another "gotcha" you haven't mentioned (probably because you haven't encountered it, yet): the behavior when inserting a field can vary between Word versions. For the "why" you'd have to ask Microsoft, but I suspect they just weren't paying attention...

    Here's a code sample that is at least "compacter", as it moves the repeating steps into separate functions.

    Sub InsertFieldsInOrder()
        Dim rngNewContent As word.Range
        
        Set rngNewContent = Selection.Range ' ActiveDocument.content
        rngNewContent.Collapse wdCollapseEnd
        
        Set rngNewContent = InsertNewText(rngNewContent, "Page ")
        Set rngNewContent = InsertAField(rngNewContent, "Page")
        Set rngNewContent = InsertNewText(rngNewContent, " of ")
        Set rngNewContent = InsertAField(rngNewContent, "NumPages")
        rngNewContent.Text = vbCr
    
    End Sub
    
    Function InsertNewText(rng As word.Range, newText As String) As word.Range
        rng.Text = newText
        rng.Collapse wdCollapseEnd
        Set InsertNewText = rng
    End Function
    
    Function InsertAField(rng As word.Range, _
                          fieldText As String) As word.Range
        
        Dim fld As word.Field
        Dim rngField As word.Range
        
        Set fld = rng.Document.Fields.Add(Range:=rng, _
                  Text:=fieldText, PreserveFormatting:=False)
        
        Set rngField = fld.result
        rngField.Collapse wdCollapseEnd
        rngField.MoveStart wdCharacter, 1
        Set InsertAField = rngField
    End Function


    Cindy Meister, VSTO/Word MVP, my blog

    Wednesday, May 14, 2014 3:15 PM
    Moderator
  • Hi Cindy!

    Once again thank you very much for sharing your vast knowledge of the field (actually, no pun intended!).

    The new element for me was the line

    Set rngField = fld.Result

    which does the trick.

    Best wishes

    Holger

    Wednesday, May 14, 2014 5:20 PM

All replies

  • Hi Holger

    There's another "gotcha" you haven't mentioned (probably because you haven't encountered it, yet): the behavior when inserting a field can vary between Word versions. For the "why" you'd have to ask Microsoft, but I suspect they just weren't paying attention...

    Here's a code sample that is at least "compacter", as it moves the repeating steps into separate functions.

    Sub InsertFieldsInOrder()
        Dim rngNewContent As word.Range
        
        Set rngNewContent = Selection.Range ' ActiveDocument.content
        rngNewContent.Collapse wdCollapseEnd
        
        Set rngNewContent = InsertNewText(rngNewContent, "Page ")
        Set rngNewContent = InsertAField(rngNewContent, "Page")
        Set rngNewContent = InsertNewText(rngNewContent, " of ")
        Set rngNewContent = InsertAField(rngNewContent, "NumPages")
        rngNewContent.Text = vbCr
    
    End Sub
    
    Function InsertNewText(rng As word.Range, newText As String) As word.Range
        rng.Text = newText
        rng.Collapse wdCollapseEnd
        Set InsertNewText = rng
    End Function
    
    Function InsertAField(rng As word.Range, _
                          fieldText As String) As word.Range
        
        Dim fld As word.Field
        Dim rngField As word.Range
        
        Set fld = rng.Document.Fields.Add(Range:=rng, _
                  Text:=fieldText, PreserveFormatting:=False)
        
        Set rngField = fld.result
        rngField.Collapse wdCollapseEnd
        rngField.MoveStart wdCharacter, 1
        Set InsertAField = rngField
    End Function


    Cindy Meister, VSTO/Word MVP, my blog

    Wednesday, May 14, 2014 3:15 PM
    Moderator
  • Hi Cindy!

    Once again thank you very much for sharing your vast knowledge of the field (actually, no pun intended!).

    The new element for me was the line

    Set rngField = fld.Result

    which does the trick.

    Best wishes

    Holger

    Wednesday, May 14, 2014 5:20 PM