How to update a Table of Tables with macro vba-Word? - vba

I'm a beginner in word-vba macros (but I quite good for excel-vba) and I'm looking to update a "Table of Tables".
I've found out how to do so for "Table of Content" and "Table of Figures" (with ActiveDocument.TablesOfContents(1).Update) but the Collection TableOfTables doesn't exist.
Does someone know what I have to do?
Thanks in advance,

There isn't a "Table of Tables" object or a TableOfTables collection. A "Table of Tables" is really just a kind of "Table of Contents". Indeed, so too is a "Table of Figures". If you look at the field codes underlying these, you'll see all three use a TOC field - a "Table of Tables" and a "Table of Figures" would have field codes like { TOC \h \z \c "Table" } and { TOC \h \z \c "Figure" }, respectively. So, if you want to update any of these (or any custom types you create), but not necessarily all, you can simply loop through the TableOfContents collection and check what follows the \c switch, if present. Likewise, you can loop through the TableOfContents collection and update all items in it. Hence:
Sub Demo()
Application.ScreenUpdating = False
Dim TOC As TableOfContents
For Each TOC In ActiveDocument.TablesOfContents
TOC.Update
'Or depending on what you want to update:
'TOC.UpdatePageNumbers
Next
Application.ScreenUpdating = True
End Sub
A simpler way - for all fields - would be:
Sub Demo()
Application.ScreenUpdating = False
With ActiveDocument
.Fields.Update
.PrintPreview
.ClosePrintPreview
End With
Application.ScreenUpdating = True
End Sub

Ok, thanks to #macropod I figure out how to solve my issue.
The 'Table of tables' is not another table of content but another table of figures
So here is my finale code :
Public Sub UpdateAllFiles()
With ActiveDocument
.TablesOfContents(1).Update
.TablesOfFigures(1).Update
.TablesOfFigures(2).Update
End With
End Sub

Related

Macro for Adding Text To Begining of Every Paragraph

I am trying to create a Word macro that will go through a large document that I have and add the text "SAMPLE" to the beginning of every paragraph.
The document contains a Title page, Table of Contents and Headings throughout and I would prefer none of these have the "SAMPLE" text on them, just the paragraphs.
Below is some macro code I have found on various sites and kind of pieced together to do somewhat of what I want. It does place the "SAMPLE" text at the beginning of some paragraphs but not all, usually only the first paragraph of a new section within my document. And it also places it at the end of the Table of Contents and Beginning of the Title page.
I am brand new to macros in Word so any help is appreciated or if there is a better way of doing this perhaps? There might even be some unnecessary bits in this code since it is pieced together from other samples.
Sub SAMPLE()
Application.ScreenUpdating = False
Dim Par As Paragraph, Rng As Range
For Each Par In ActiveDocument.Paragraphs
If Par.Style = "Normal" Then
If Rng Is Nothing Then
Set Rng = Par.Range
Else
Rng.End = Par.Range.End
End If
Else
Call RngFmt(Rng)
End If
If Par.Range.End = ActiveDocument.Range.End Then
Call RngFmt(Rng)
End If
Next
Application.ScreenUpdating = True
End Sub
Sub RngFmt(Rng As Range)
If Not Rng Is Nothing Then
With Rng
.End = .End - 1
.InsertBefore "SAMPLE"
End With
Set Rng = Nothing
End If
End Sub
Provided your Title, Table of Contents and Headings etc. don't use the Normal Style - as they shouldn't - you really don't need a macro for this - all you need is a wildcard Find/Replace where:
Find = [!^13]*^13
Replace = SAMPLE: ^&
and you specify the Normal Style as a Find formatting parameter. You could, of course, record the above as a macro, but that seems overkill unless you're doing this often.

Validating Cell Input Based on Another Cell

When I input some text in a cell, for example in cell B2-test, I want in cell A6 the input to begin with this string and to end with _VAR1-for example test_VAR1.
I have found a simple solution as formula - =IF(A2="test","test_VAR1") but I want to make it as a VBA code.
So any idea how this can be done?
This is the most minimal example that I can come up with.
The LCase(Range("B2")) would also take "Test" and "TeSt" into account:
Option Explicit
Public Sub TestMe()
With ActiveSheet
If LCase(.Range("B2")) = "test" Then
.Range("A6") = .Range("B2") & "_VAR1"
End If
End With
End Sub
And if you want to check every event of the worksheet, put your code in the corresponding worksheet (Sheet1, Sheet2 and Sheet3 on the picture below):
Option Explicit
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Cells.Count > 1 Then Exit Sub
If Intersect(Target, Me.Range("B2")) Is Nothing Then Exit Sub
Application.EnableEvents = False
If LCase(Target) = "test" Then
Me.Range("A6") = Target & "_VAR1"
End If
Application.EnableEvents = True
End Sub
I know you said in your question you wanted macro, but I'm not going to post my own (because I feel like #Vityata's answer should be sufficient)
However, I got impression from your post, that you could adjust / improve your formula instead and avoid macro altogether. It's usually better to avoid macro, when possible, for compatibility reasons (a lot of users have macros disabled by default)
If you simply want to add the keyword "_VAR1" to the input, use the following formula instead
=LTRIM(B2) & "_VAR1"
If the input can be anything, that contains the word "test"
=IF(ISNUMBER(SEARCH("test", TRIM(LOWER(B2)))), LTRIM(B2) & "_VAR1", "Incorrect Input")
The text contains only the word "test" and nothing else
=IF(TRIM(LOWER(B2))="test", LTRIM(B2) & "_VAR1", "Incorrect input"
There are some other variations / tricks you could do with this, but these are some of the most basic examples you can use as your "building blocks"

Updating table of contents in word

I have a macro for my word document which is meant to update all the fields and all the table of contents.
Sub UpdateFields()
Dim oStory As Range
For Each oStory In ActiveDocument.StoryRanges
oStory.Fields.Update
If oStory.StoryType <> wdMainTextStory Then
While Not (oStory.NextStoryRange Is Nothing)
Set oStory = oStory.NextStoryRange
oStory.Fields.Update
Wend
End If
Next oStory
Set oStory = Nothing
Dim TOC As TableOfContents
For Each TOC In ActiveDocument.TablesOfContents
TOC.Update
Next
End Sub
However, when it is run I get this error.
Error and then debug below
I would appreciate any help in fixing the problem.
The issue is caused by naming the sub UpdateFields. For unknown reasons this name is reserved in Word VBA. Rename the sub to an allowed name (for example, FieldUpdates) and the code will work fine.
The error thrown indicates that the TableOfContents specified for update doesn't exist. Word will produce errors of this type when using For ... Each loops to access some of its collections. The number of TOCs Word is aware of may have changed while editing the document. To avoid the error, avoid For ... Each enumerations. Use code like the following instead.
Dim i As Integer
With ActiveDocument
For i = 1 To .TablesOfContents.Count
.TableOfContents(i).Update
Next i
End With

Macro to update all fields in a word document

I have built - over the years - a vba macro that is supposed to update all fields in a word document.
I invoke this macro before releasing the document for review to ensure all headers and footers etc are correct.
Currently - it look like this:
Sub UpdateAllFields()
'
' UpdateAllFields Macro
'
'
Dim doc As Document ' Pointer to Active Document
Dim wnd As Window ' Pointer to Document's Window
Dim lngMain As Long ' Main Pane Type Holder
Dim lngSplit As Long ' Split Type Holder
Dim lngActPane As Long ' ActivePane Number
Dim rngStory As Range ' Range Objwct for Looping through Stories
Dim TOC As TableOfContents ' Table of Contents Object
Dim TOA As TableOfAuthorities 'Table of Authorities Object
Dim TOF As TableOfFigures 'Table of Figures Object
Dim shp As Shape
' Set Objects
Set doc = ActiveDocument
Set wnd = doc.ActiveWindow
' get Active Pane Number
lngActPane = wnd.ActivePane.Index
' Hold View Type of Main pane
lngMain = wnd.Panes(1).View.Type
' Hold SplitSpecial
lngSplit = wnd.View.SplitSpecial
' Get Rid of any split
wnd.View.SplitSpecial = wdPaneNone
' Set View to Normal
wnd.View.Type = wdNormalView
' Loop through each story in doc to update
For Each rngStory In doc.StoryRanges
If rngStory.StoryType = wdCommentsStory Then
Application.DisplayAlerts = wdAlertsNone
' Update fields
rngStory.Fields.Update
Application.DisplayAlerts = wdAlertsAll
Else
' Update fields
rngStory.Fields.Update
If rngStory.StoryType <> wdMainTextStory Then
While Not (rngStory.NextStoryRange Is Nothing)
Set rngStory = rngStory.NextStoryRange
rngStory.Fields.Update
Wend
End If
End If
Next
For Each shp In doc.Shapes
If shp.Type <> msoPicture Then
With shp.TextFrame
If .HasText Then
shp.TextFrame.TextRange.Fields.Update
End If
End With
End If
Next
' Loop through TOC and update
For Each TOC In doc.TablesOfContents
TOC.Update
Next
' Loop through TOA and update
For Each TOA In doc.TablesOfAuthorities
TOA.Update
Next
' Loop through TOF and update
For Each TOF In doc.TablesOfFigures
TOF.Update
Next
' Header and footer too.
UpdateHeader
UpdateFooter
' Return Split to original state
wnd.View.SplitSpecial = lngSplit
' Return main pane to original state
wnd.Panes(1).View.Type = lngMain
' Active proper pane
wnd.Panes(lngActPane).Activate
' Close and release all pointers
Set wnd = Nothing
Set doc = Nothing
End Sub
Sub UpdateFooter()
Dim i As Integer
'exit if no document is open
If Documents.Count = 0 Then Exit Sub
Application.ScreenUpdating = False
'Get page count
i = ActiveDocument.BuiltInDocumentProperties(14)
If i >= 1 Then 'Update fields in Footer
For Each footer In ActiveDocument.Sections(ActiveDocument.Sections.Count).Footers()
footer.Range.Fields.Update
Next
End If
Application.ScreenUpdating = True
End Sub
'Update only the fields in your footer like:
Sub UpdateHeader()
Dim i As Integer
'exit if no document is open
If Documents.Count = 0 Then Exit Sub
Application.ScreenUpdating = False
'Get page count
i = ActiveDocument.BuiltInDocumentProperties(14)
If i >= 1 Then 'Update fields in Header
For Each header In ActiveDocument.Sections(ActiveDocument.Sections.Count).Headers()
header.Range.Fields.Update
Next
End If
Application.ScreenUpdating = True
End Sub
I have noticed recently that it sometimes misses some sections of the document. Today it missed First page footer -section 2- (the document version was not updated).
I have built this macro over a number of years and several bouts of research but I am not proud of it so please suggest a complete replacement if there is now a clean way of doing it. I am using Word 2007.
To test, create a word document and add a custom field named Version and give it a value. Then use that field {DOCPROPERTY Version \* MERGEFORMAT } in as many places as you can. Headers, Footers, first-page, subsequent page etc. etc. Remember to make a multi-section document with different header/footers. Then change the property and invoke the macro. It currently does quite a good job, handling TOCs and TOAs an TOFs etc, it just seems to skip footers (sometimes) in a multi-section document for example.
Edit
The challenging document that seems to cause the most problems is structured like this:
It has 3 sections.
Section 1 is for the title page and TOC so the first page of that section has no header/footer but does use the Version property on it. Subsequent pages have page numbering in roman numerals for the TOC.
Section 2 is for the body of the document and has headers and footers.
Section 3 is for the copyright blurb and this has a very strange header and a cut-down footer.
All footers contain the Version custom document property.
My code above seems to work in all cases except sometimes it misses first page footer of sections 2 and 3.
For years, the standard I've used for updating all fields (with the exception of TOC, etc. which are handled separately) in a document is the one the Word MVPs use and recommend, which I'll copy here. It comes from Greg Maxey's site: http://gregmaxey.mvps.org/word_tip_pages/word_fields.html. One thing it does that I don't see in your version is update any fields in Shapes (text boxes) in the header/footer.
Public Sub UpdateAllFields()
Dim rngStory As Word.Range
Dim lngJunk As Long
Dim oShp As Shape
lngJunk = ActiveDocument.Sections(1).Headers(1).Range.StoryType
For Each rngStory In ActiveDocument.StoryRanges
'Iterate through all linked stories
Do
On Error Resume Next
rngStory.Fields.Update
Select Case rngStory.StoryType
Case 6, 7, 8, 9, 10, 11
If rngStory.ShapeRange.Count > 0 Then
For Each oShp In rngStory.ShapeRange
If oShp.TextFrame.HasText Then
oShp.TextFrame.TextRange.Fields.Update
End If
Next
End If
Case Else
'Do Nothing
End Select
On Error GoTo 0
'Get next linked story (if any)
Set rngStory = rngStory.NextStoryRange
Loop Until rngStory Is Nothing
Next
End Sub
Some research and experimentation produced the following addition which seems to solve the additional problem of updating the headers/footers in a multi-section document.
Add the following dimensions to the earlier answer:
dim sctn as Word.Section
dim hdft as Word.HeaderFooter
And then, add to the earlier code
for each sctn in doc.Sections
for each hdft in sctn.Headers
hdft.Range.Fields.Update
next
for each hdft in sctn.Footers
hdft.Range.Fields.Update
next
next
However - I am still not happy with this code and would very much like to replace it with something less hacky.
Thanks for these answers! I found the answers very good and learned some stuff about ms-word macros. I thought I'd make my own answer for consideration (and adding some more search engine keywords - my searches didn't bring me here immediately).
I took inspiration from the citations in the footnotes.
I had an issue where MS Word fields were not updating in Textbox (Shapes).
I was working on a 70 page word document (Word 2013) that contained a lot of figures/images/captions and cross-references. A common practice is for an image to be captioned e.g. Figure 7, so it can be easily cross-referenced. Often the caption is inside a textbox (shape) and grouped with/to the object its captioning.
So after some document editing and content reorganisation, the fields and cross-references can easily get out of logical sequence.
OK - no problem... pressing CTRL+A then F9 to update the document fields should solve this?
Unfortunately that didn't work as expected to update fields in textboxes (shapes).
In this scenario where fields exist inside textboxes (shapes) CTRL+A then F9 only updated the fields not inside a textbox (shape).
One can assume this behaviour is because field updating (F9) works on selected text, and with the CTRL+A then F9 approach only text outside of the textboxes (shapes) is selected, so the field update only applies outside of textboxes (shapes).
I'm surprised there is not a button on the ribbon to perform an "update all fields". There could even be a toggle option to prompt the user to update all fields when closing a document?
I checked Word's (2013) ribbon command list, and didn't find an Update All command.
Solution UpdateAllFields()
Like the code shared by #Cindy here, the following code should update fields wherever they are in the doc, header, footer, main doc, textbox, grouped and nested grouped textbox.
Create a macro with the following code, and then add to the Quick Access Toolbar (QAT)
Press ALT+F8 to open the Macros dialogue.
Enter a name for the Macro: UpdateAllFields
Press Create button
Paste the code:
Sub UpdateAllFields()
Application.ScreenUpdating = False
With ActiveDocument
.Fields.Update
.PrintPreview
.ClosePrintPreview
End With
Application.ScreenUpdating = True
End Sub
Finally add the Macro to the Quick Access Toolbar.
Citations and inspirations:
The Q&A's in this post!
There is a related post on the Microsoft Community here: Word 365 Fields not updating in Textbox [serious reproducible error]. This suggests the issue is present in at least Word 2013 and Word 365.
There is a related post on Stack Overflow here: Macro to update fields in shapes (textboxes) in footer in Microsoft Word.
Another example UpdateTextboxFields()
This was the first version of code I wrote as I was in research and solution mode. Its a recursive approach to update fields inside textboxes, even if they are inside a group, or nested group. This doesn't update fields outside shapes.
Public Sub UpdateTextboxFields()
Application.ScreenUpdating = False
With ActiveDocument
Call IterateShapesCollection(.Shapes)
.PrintPreview
.ClosePrintPreview
End With
Application.ScreenUpdating = True
End Sub
Private Sub IterateShapesCollection(col)
Dim shp As Shape
For Each shp In col
' https://learn.microsoft.com/en-gb/office/vba/api/office.msoshapetype
' Ignore images and
If 1 = shp.Type Or 13 = shp.Type Then
GoTo NextIteration
End If
'Debug.Print ("Name: " & shp.Name & ", Type: " & shp.Type)
' if the type is a group, recurse
If 6 = shp.Type Then
Call IterateShapesCollection(shp.GroupItems)
Else
Call UpdateShapeFields(shp)
End If
NextIteration:
Next
End Sub
Private Sub UpdateShapeFields(shp)
With shp.TextFrame
If .HasText Then
.TextRange.Fields.Update
End If
End With
End Sub
Word display option: Update fields before printing
cite: Microsoft article Some fields are updated while other fields are not
The concept behind this option/approach is: all document fields are updated when you open print preview.
It looks like this option in Word (tested in 2013) updates all fields with a caveat - see below - you may need to open and close print preview twice.
File → Options → Display → Print options section → Update fields before printing
Caveat if the doc has cross-references to figures/captions
This caveat applies to the word "Update fields before printing" display option and the UpdateAllFields() macro.
IF the document contains cross-references to figures/captions (with numbers), and those figures/captions have changed sequence/place in the document...
You must update the fields twice, 1) to reflect the figures/captions update, and then 2) to update the cross-references.

VBA Word: How can I find in which table something (i.e. selection) is?

I have in my word document many tables, each is linked to bookmark.
Then I have function which scan document for each tracked change (revisions).
How can I find out where my tracked change is? in which table?
Here is some of my code:
Dim ThisWord As Document, TabHead As Table
Set ThisWord = ActiveDocument
Set TabHead = ThisWord.Bookmarks("Head").Range.Tables(1) '"Head" is bookmark for my first table
For Each oRevision In ThisWord.Revisions 'Run through each revision - tracked change
Select Case oRevision.Type
Case wdRevisionInsert
strText = oRevision.Range.Text
If oRevision.Range.Information(wdWithInTable) = True Then 'Check if tracked change is within table
Select Case oRevision.Range.Table ' <-- How can I change this part???
Case TabHead
'do some stuff with strText
'Case AnotherTable1
'Case AnotherTable2
'...
end select
end if
end select
next oRevision
My main goal is to track down all changes in word document, get date and time and user of that change. By I need to know where that change was made. Tracked change function can give me all that detail, but how to determine where that change was made?
Through the Range object, you have acces to all the different objects in the revision. If you want to reference the first Table object then use:
oRevision.Range.Tables(1)
You obviously need to check to see that there are tables before using the reference (e.g If oRevision.Range.Tables.Count > 0 Then ...).
You could also access the bookmarks collection in the same way:
If oRevision.Range.Bookmarks.Count > 0 Then
Debug.Print oRevision.Range.Bookmarks(1).Name
End If
This gives you the table number of Selection.
Sub Demo()
Dim iTable&
With Selection
If Not .Information(wdWithInTable) Then
MsgBox "The selection is not in a table!"
Exit Sub
End If
For iTable = 1 To ActiveDocument.Tables.Count
If (.Range.Start >= ActiveDocument.Tables(iTable).Range.Start) And _
(.Range.End <= ActiveDocument.Tables(iTable).Range.End) Then
Exit For
End If
Next iTable
End With
MsgBox "It's in table # " & iTable
End Sub
From macropod https://groups.google.com/forum/#!searchin/microsoft.public.word.programming/%22table%22$20which/microsoft.public.word.programming/Gid7abgeAek/c5rUWhFmWwgJ