Consulting

Results 1 to 13 of 13

Thread: Using InsertFile method to insert into a BookMark

  1. #1

    Using InsertFile method to insert into a BookMark

    Hi All,

    I have a word document where I use "building blocks" being seperate word documents that I insert into the main document. I can InsertFile the text, I can even place it at a bookmark - but I want the option of eing able to delete the block using VBA, but I can't seem to encapsulate the insertfile text into a bookmark.

    The first example is what I get, the second is what I want: https://pasteboard.co/JOcISUG.jpg

    Does anyone have any ideas how I can insert the text into the bookmark, or set the bookmark afterwards (but how do I get the range), or some other way of achieving this functionality?

    Thanks

  2. #2
    Microsoft Word MVP 2003-2009 VBAX Guru gmaxey's Avatar
    Joined
    Sep 2005
    Posts
    3,335
    Location
    If your bookmark stands alone in a paragraph, you can do it like this:

    Sub ScratchMacroII()
    'A basic Word macro coded by Greg Maxey
    Dim oRng As Range
      Set oRng = ActiveDocument.Bookmarks("bmTarget").Range
      oRng.InsertFile "D:\FileToInsert.docm"
      Set oRng = oRng.Paragraphs(1).Range
      oRng.End = oRng.End - 1
      ActiveDocument.Bookmarks.Add "bmTarget", oRng
    lbl_Exit:
      Exit Sub
    End Sub
    Greg

    Visit my website: http://gregmaxey.com

  3. #3
    Microsoft Word MVP 2003-2009 VBAX Guru gmaxey's Avatar
    Joined
    Sep 2005
    Posts
    3,335
    Location
    Or maybe this:

    Sub ScratchMacro()
    'A basic Word macro coded by Greg Maxey
    Dim oRng As Range
    Dim oRngNC As Range
      Set oRng = ActiveDocument.Bookmarks("bmTarget").Range
      Set oRngNC = oRng.Characters.Last
      oRng.InsertFile ("D:\FileToInsert.docm")
      oRngNC.End = oRngNC.End - 1
      ActiveDocument.Bookmarks.Add "bmTarget", oRngNC
    lbl_Exit:
      Exit Sub
    End Sub
    Greg

    Visit my website: http://gregmaxey.com

  4. #4
    Hi Greg,

    Wow, that's had me stumped for the longest time, definitely works for me - I can now insert and delete blocks. Thank you!

    For some reason it adds a new line with every time I run the code, but the new line character is outside the bookmark. I'm not sure if it is being imported from the file and then ignored or if the bookmark range is just a little off?

    Actually, I do think its something to do with the range. What does this line do, why subtract the one? I changed it to + 1 and now it encapuslates the new line character that was previously left out, but I'm not sure if that is the correct fix.

    oRng.End = oRng.End - 1

  5. #5
    ah, I see what you mean about the paragraph - lots of my documents do have multiple paragraphs, tables - some even have a book mark or two of their own. Can Word handle such insertions into bookmarks?

  6. #6
    Microsoft Word MVP 2003-2009 VBAX Guru gmaxey's Avatar
    Joined
    Sep 2005
    Posts
    3,335
    Location
    That extra line is a result of the final paragraph in the file to insert. You could trim it as follows. Yes, files to insert can have multiple paragraphs and bookmarks (as long a one of the bookmarks is not named bmTarget).

    Sub ScratchMacro()
    'A basic Word macro coded by Greg Maxey
    Dim oRng As Range
    Dim oRngNC As Range
      Set oRng = ActiveDocument.Bookmarks("bmTarget").Range
      Set oRngNC = oRng.Characters.Last
      oRng.InsertFile ("D:\FileToInsert.docm")
      oRngNC.Characters.Last.Previous.Delete 'Added
      oRngNC.End = oRngNC.End - 1
      ActiveDocument.Bookmarks.Add "bmTarget", oRngNC
    lbl_Exit:
      Exit Sub
    End Sub
    Greg

    Visit my website: http://gregmaxey.com

  7. #7
    Hi Greg,

    Thank you! Yes that was exactly it, they are now inserting perfectly, I can edit, remove and select the blocks beautifully.

    Wish I'd had found https://gregmaxey.com/word_tip_pages..._bookmark.html prior to asking here!

    I do have an issue where some of the blocks don't contain a double paragraph mark at the end (which was giving me the problem initally), but I think the solution will be to simply add it to the few that are missing it, or remove all of them. I think the former will be easier as it appears far more often.

    So far I've been testing whether "bm_target" exists, with numbers appended for multiple bookmarks, and if it doesn't then I insert a new bookmark:

     ActiveDocument.Bookmarks.Add Name:=BMVAR, Range:=ActiveDocument.Paragraphs(ActiveDocument.Paragraphs.Count).Range
    But that places the new bookmark at the last paragraph. If I insert a block that doesn't contain that last paragraph, the next bookmark is inserted within the last part of the previous bookmark and the whole process breaks down (partially). But that brought me to another issue, since I didn't really want to just insert blocks at the end - wanting to allow users to insert blocks at arbitrary locations, as some pre-defined templates have several pages and blocks need to be inserted in the middle. As I can check whether a bookmark at selection exists, how can I insertparagraphafter and also select that paragraph as range for bookmark insertion?

    On Error Resume Next
    Dim BMRng As Word.Range
    
    
    If Selection.Bookmarks(1).Name <> "" Then 'we are in a bookmark, so make a paragraph and then insert the next BM.
        ActiveDocument.Bookmarks.Item("Test_BM").Range.InsertParagraphAfter 'works but how do I select this
        Selection.TypeText "Test" 'currently types inside my bookmark
        
    End If
    
    
    If Err.Number = 5941 Then MsgBox "We are not in a BM" ' We are not in a bookmark can insert new block at selection
    Any pointers would be great! I haven't responded until now as I was trying to find a solution on my own...

  8. #8
    Microsoft Word MVP 2003-2009 VBAX Guru gmaxey's Avatar
    Joined
    Sep 2005
    Posts
    3,335
    Location
    I don't really understand the problem. Bookmarks are a bit dated in the modern world. Why don't you use a richtext content control:

    Sub ScratchMacro()
    'A basic Word macro coded by Greg Maxey
    Dim oRng As Range
    Dim oRngNC As Range
      Set oRng = ActiveDocument.SelectContentControlsByTitle("CCTarget").Item(1).Range
      oRng.InsertFile ("D:\FileToInsert.docm")
      Set oRng = ActiveDocument.SelectContentControlsByTitle("CCTarget").Item(1).Range
      oRng.Characters.Last.Delete
    lbl_Exit:
      Exit Sub
    End Sub
    Greg

    Visit my website: http://gregmaxey.com

  9. #9
    Thanks! I haven't used them much, but they are quite cool - I do like that I can set a title, should make management a little easier.

    However, I have the same issue as I do with bookmarks, when I place the insertion point in the middle of my document, how can I insert multiple blocks one after another? As it stands the insertion point remains at the top / front and a subsequent content control is inserted inside the recent control. Say I want to quickly import three user selected documents:

        'A basic Word macro coded by Greg Maxey / modified by Kay
        Dim oRng As ContentControl
        Set oRng = ActiveDocument.ContentControls.Add(wdContentControlRichText)
        oRng.Range.InsertFile ("E:\Templates\Template Building Blocks\block1.docx") 
        oRng.Title = "This is a great block!"
        oRng.Range.Select
        ActiveDocument.Fields.Update
    Thank you
    Kay

  10. #10
    For two or more controls you need to reset the range position after inserting the controls e.g. as follows. You can follow the process for more controls as required.

    Dim oCC As ContentControl
    Dim oRng As Range
        'Set a range where you want the first control
        Set oRng = Selection.Range
        'Ensure that the range does not include a selection of text
        oRng.Collapse 0
    
    
        'add a content control to the range
        Set oCC = ActiveDocument.ContentControls.Add(wdContentControlRichText, oRng)
        oCC.Title = "This is a great block!"
        oCC.Tag = oCC.Title
        Set oRng = oCC.Range
        oRng.InsertFile ("E:\Templates\Template Building Blocks\block1.docx")
    
    
        'Move the end of the range out of the control
        oRng.End = oRng.End + 1
    
    
        'Collapse the range and type a space
        oRng.Collapse 0
        oRng.Text = " "
    
    
        'Collapse the range again and add another content control
        oRng.Collapse 0
        Set oCC = ActiveDocument.ContentControls.Add(wdContentControlRichText, oRng)
        oCC.Title = "This is another CC"
        oCC.Tag = oCC.Title
        Set oRng = oCC.Range
        oRng.InsertFile ("E:\Templates\Template Building Blocks\block2.docx")
    If you want to insert both texts in the same control, the method is similar e.g.
    Dim oCC As ContentControl
    Dim oRng As Range
        'Set a range where you want the control
        Set oRng = Selection.Range
        'Ensure that the range does not include a selection of text
        oRng.Collapse 0
    
    
        'add a content control to the range
        Set oCC = ActiveDocument.ContentControls.Add(wdContentControlRichText, oRng)
        oCC.Title = "This is a great block!"
        oCC.Tag = oCC.Title
        Set oRng = oCC.Range
        'Insert the first file
        oRng.InsertFile ("E:\Templates\Template Building Blocks\block1.docx")
      
        'Collapse the range and type a space
        oRng.Collapse 0
        oRng.Text = " "
    
    
        'Collapse the range again and add another text
        oRng.Collapse 0
        oRng.InsertFile ("E:\Templates\Template Building Blocks\block2.docx")
    Graham Mayor - MS MVP (Word) 2002-2019
    Visit my web site for more programming tips and ready made processes
    http://www.gmayor.com

  11. #11
    Microsoft Word MVP 2003-2009 VBAX Guru gmaxey's Avatar
    Joined
    Sep 2005
    Posts
    3,335
    Location
    This is just a variation of Graham's working solution. It does address the extra paragraph that results when inserting a file:

    Sub ScratchMacro()
    'A basic Word macro coded by Greg Maxey
    Dim oCC As ContentControl
    Dim oRng As Range
    Dim lngFile As Long
    Dim varFiles
      'Set a range where you want the first control
      Set oRng = Selection.Range
      'Ensure that the range does not include a selection of text
      oRng.Collapse 0
      varFiles = Split("Block1|Block2|Block3", "|")
      For lngFile = 0 To UBound(varFiles)
        'Add a content control to the range
        Set oCC = ActiveDocument.ContentControls.Add(wdContentControlRichText, oRng)
        oCC.Title = varFiles(lngFile)
        oCC.Range.InsertFile "E:\Templates\Template Building Blocks\" & varFiles(lngFile) & ".docx"
        Set oRng = oCC.Range
        oRng.Characters.Last.Delete
        'Move the end of the range out of the control
        oRng.End = oRng.End + 2
        oRng.Collapse 0
      Next lngFile
    lbl_Exit:
      Exit Sub
    End Sub
    Greg

    Visit my website: http://gregmaxey.com

  12. #12
    Thank you Graham and Greg, I am extremely grateful for your help with this!

    Consider this scenario - I have a userform with a treeview control that I populate with 10 files for textblock selection. A user selects an area on their document that they would like to insert the textblock, clicks on one of the blocks and it either insers a bookmark or richtext CC, then inserts the textblock text from an external document. The most likely scenario is the user then selects the next textblock from the treeview to insert below the first. Unfortunately with both your examples I am working relative to the original content control with each subsequent control - however when the sub exits I also lose that object, the selection.range is not updated to be outside of the control.

    I was thinking I could store the last object range as public, so that I can refer to it on subsequent insertions, then step out, collapse and insert new CC, update public range - but what if the user selects another location, or wants to insert a content control between two others. Is there any way to set the selection.range to be just following my last contentCC or bookmark, so that I can reference at a later time, or use the current selection.range should the user have changed it?

    I could potentially return my userform to modal, thereby not allowing the user to change the selection once they've opened the userform, and on the next userform load I can reset the current range to selection.range, then save the last range.end so I can continue from there?

  13. #13
    I put that last thought I had into code and this definitely will work for me (as long as the user is prevented from moving the insertion point, expecting it to be inserted there, so will need a modal form. That way I can also undo the last insertion (to be used as a preview feature).

    Public TestRng As Range
    
    
    Private Sub UserForm_Initialize()
    	Set TestRng = Selection.Range   
    End Sub
    
    
    Private Sub TreeView1_click()
    Dim oCC As ContentControl
    Dim oRng As Range
     
    If TreeView1.SelectedItem.Tag = "" Then Exit Sub 'only tagged items are files
    
    
    	'Ensure that the range does not include a selection of text
    	TestRng.Collapse 0
      
    	'Add a content control to the range
        Set oCC = ActiveDocument.ContentControls.Add(wdContentControlRichText, TestRng)
        oCC.Title = TreeView1.SelectedItem.Text
        oCC.Range.InsertFile TreeView1.SelectedItem.Key
        Set TestRng = oCC.Range
        
    	'oRng.Characters.Last.Delete
        'Move the end of the range out of the control
        TestRng.End = TestRng.End + 2
        TestRng.Collapse 0
    
    
    End Sub
    Unless you can think of a better way? I would like to prevent a modal form if possible, and give the users more control over where they can place text boxes without having to come out and back into the 'program'.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •