Removing the Contents from the Cell of a Word Table using Excel VBA - vba

I am currently working on a project and am looking for some assistance. To give you guys a layout of what is happening, I will run through the scenario step by step.
1) Currently I have a string array called “AnimalNamesToRemove” (For this example the array with contain the following words), that contains words that are used as bookmarks in a word document that I am looking to remove off a word table referenced below:
AnimalNamesToRemove
AnimalCat, AnimalDog, AnimalBird
2) In addition to the array, a table in a word document exists that has the name of the animal in column one, as well as some information about the animal (the only information that is of importance is the name of the animal):
Word Table
3) For this scenario, I have an excel table that I am looking to use to reference the words in the array and the word table names, as there are already bookmarks in the word document being used that hold the names existing in the array. To bring these together, a two column excel spreadsheet exists that has the name of the bookmark and the actual animal name (Column two is referenced using the range named “myRangeRef”):
Spreadsheet
4) What I am looking to do is that for every value in the array stated above, if that value (ex. “AnimalDog”) is found in the spreadsheet table (i.e. column two “Bookmark Reference”) then offset to the respective cell beside it in the first column (i.e. “Dog”) and create a new comma delimited string with those values, the same as “AnimalNamesToRemove” (i.e. Cat, Dog, Bird) and then turn it into a string array named “AnimalsToDelete”. Once the array is created, and all the values have been selected in the first column and made into an array based on the reference in column two, I want to go row by row in the word table and for every value existing in the new array “AnimalsToDelete”, if that value (i.e. Cat, Dog, and Bird) exists in the word table (found in column one), I want the code to delete the entire row that the name is found in (see result shown below)
Example Result
Dim wdTable As Object
Dim myRangeRef As Range
Dim AnimalNamesToRemove As Variant
Dim AnimalsToDelete As Variant
Dim wdDoc As Object
Set myRangeRef = ThisWorkbook.Sheets("Bookmark References").Range("B1:B6")
Set wdTable = wdDoc.Tables(1)
For i = LBound(AnimalNamesToRemove) To UBound(AnimalNamesToRemove)
For Each cell In myRangeRef
If InStr(1, cell.Value, AnimalNamesToRemove(i), vbTextCompare) Then
aCell = cell.Offset(, -1).Value
stTemp = stTemp & "," & aCell
End If
Next cell
Next i
stTemp = Mid(stTemp, 2)
If Not Len(Trim(stTemp)) = 0 Then
AnimalsToDelete = Split(stTemp, ",")
For i = LBound(AnimalsToDelete) To UBound(AnimalsToDelete)
For j = wdTable.Rows.Count To 2 Step -1
If wdTable.cell(j, 1).Range.Text = AnimalsToDelete(i) Then wdTable.Rows(j).Delete
Next j
Next i
End If
If you have any solutions and/or suggestions please comment them down below.
NOTE: The first section of code works for creating the string array (i.e. from "set wdTable =" to "next i"), its the removal of information from the word table that I'm having the issues with.
Best,
Jack Henderson

Alright, based on your code I added a Reference to the Microsoft Word 16.0 Object Library in my Excel VBE (Tools - References, check the box) so we have the Word stuff available.
Next I wrote the following procedure:
Sub Test()
Dim BookMarksToDelete() As String
Dim ReturnsToDelete() As String
Dim wApp As Word.Application
Dim wDoc As Word.Document
Dim wdTable As Word.Table
Dim myRangeRef As Range
Dim cel As Range
Dim aCell As String
Set wApp = New Word.Application
Set wDoc = wApp.Documents.Open("C:\Temp\Col1.docx")
Set wdTable = wDoc.Tables(1)
ReDim BookMarksToDelete(0 To 1)
BookMarksToDelete(0) = "BlahOne"
BookMarksToDelete(1) = "BlahThree"
Set myRangeRef = Worksheets("Sheet1").Range("B1:B5")
For i = LBound(BookMarksToDelete) To UBound(BookMarksToDelete)
For Each cel In myRangeRef
If InStr(1, cel.Value, BookMarksToDelete(i), vbTextCompare) Then
aCell = cel.Offset(0, -1).Value
stTemp = stTemp & "," & aCell
End If
Next cel
Next i
stTemp = Mid(stTemp, 2)
If Not Len(Trim(stTemp)) = 0 Then
ReturnsToDelete = Split(stTemp, ",")
For i = LBound(ReturnsToDelete) To UBound(ReturnsToDelete)
For j = wdTable.Rows.Count To 2 Step -1
If Left(wdTable.cell(j, 1).Range.Text, Len(wdTable.cell(j, 1).Range.Text) - 2) = ReturnsToDelete(i) Then
wdTable.Rows(j).Delete
End If
Next j
Next i
End If
wDoc.Save
wDoc.Close
wApp.Quit
Set wdTable = Nothing
Set wDoc = Nothing
Set wApp = Nothing
Set myRangeRef = Nothing
End Sub
As you can see, I basically stuck to your exact same structure and it works perfectly.
Your main issue (the rows in the word doc not being deleted or found) is because the text in a Cell in a table in word actually contains 2 extra characters in the very end. One is a "fake new line" and the other one shows up when you hit this paragraph button on the word GUI - It's an "end of cell" marker.
See for example this discussion
EDIT I based myself on the "BlahOne" and "NameOne" example, but yeah, you can edit it for animals, of course...

Related

MS Word - find table rows with wrapped text

I have a table where all cells have Cell.WordWrap set to true. Some of them have text longer than cell width so it's wrapped. I need to find them (with longer text) and set them Cell.FitText = True, but can't figure how.
I tried to read row/cell .height. But it does not return real row/cell height but minimum height regardless how Cell.HeightRule is set.
Thanks for your tips!
One way to determine whether the content of a cell wraps is to compare the line numbering of the start and end of the cell content, as demonstrated in the following code example.
The Word object model provides the Information property, which has numerous enumeration members, including wdFirstCharacterLineNumber.
Each cell in a table is checked in a loop. After determining the line number of the first character in the cell, the Range is collapsed to its end-point (which is the beginning of the next cell), then moved back one character (putting it in the original cell) and the line number of the last character in the cell is checked.
If the second is greater than the first, the cell is added to an array. (Note: possibly, you could process the cell directly. But if this could affect other cells, better to add them all to an array, first, then process the array.)
Finally, the array is looped and each cell formatted with FitText = True
Sub ChangeCellWrapForLongLinesOfText()
Dim tbl As Word.Table
Dim cel As Word.Cell
Dim rngCel As Word.Range
Dim multiLineCells() As Word.Cell
Dim firstLine As Long
Dim lastLine As Long
Dim i As Long, x As Long
Set tbl = ActiveDocument.Tables(1)
For Each cel In tbl.Range.Cells
Set rngCel = cel.Range
firstLine = rngCel.Information(wdFirstCharacterLineNumber)
rngCel.Collapse wdCollapseEnd
rngCel.MoveEnd wdCharacter, -1
lastLine = rngCel.Information(wdFirstCharacterLineNumber)
If lastLine > firstLine Then
ReDim Preserve multiLineCells(i)
Set multiLineCells(i) = cel
i = i + 1
End If
Next
'Debug.Print i, UBound(multiLineCells())
For x = LBound(multiLineCells()) To UBound(multiLineCells())
'Debug.Print multiLineCells(x).Range.Text
multiLineCells(x).FitText = True
Next
End Sub

Writing Excel data to Word content controls without error messages

This question is about using content controls to move data values from Excel to Word in VBA. Please note I have enabled the "Microsoft Word 16.0 Object Library" under references in the MSExcel VBA environment.
My project needs to send Excel data to specific places in a Word document.
PROBLEM: It seems I am not using the contentcontrols properly and keep getting runtime errors I'm not finding much information about. Either RTE-438
Object doesen't support this method
or RTE-424
Object Required
Description of what the code does: There are two baseline workbooks with multiple worksheets. Another analysis workbook uses each of these is programmed with VLOOKUP(INDIRECT...),) to generate tables for reports put into a word document. A Variant is used to change the tabs being sourced in the baseline workbook. The analysis is basically CATS-DOGS=PETS. on each cycle through, tables that are not informational (no difference between two baseline workbooks) are skipped and the next tab is analyzed. If a table is informative, then a PDF is produced. The report (a Word document) is updated. Table is added to the report. Upon completion, the next tab or evaluation table is considered.
Sub CommandButton1_Click()
Dim Tabs(0 To 18) As Variant
Tabs(0) = "01"
Tabs(1) = "02"
Tabs(2) = "03"
Tabs(3) = "03"
Tabs(4) = "04"
Tabs(5) = "05"
Tabs(6) = "06"
Tabs(7) = "07"
Tabs(8) = "08"
Tabs(9) = "09"
Tabs(10) = "10"
Tabs(11) = "11"
Tabs(12) = "12"
Tabs(13) = "13"
Tabs(14) = "14"
Tabs(15) = "15"
Tabs(16) = "16"
Tabs(17) = "17"
Tabs(18) = "18"
Dim xlApp As Object
On Error Resume Next
Set xlApp = GetObject("excel.applicaiton")
If Err.Number = 429 Then
Err.Clear
Set xlApp = CreateObject("excel.applicaiton")
End If
On Error GoTo 0
Dim controlThis As String ' the controlThis variable is to the address of the particular data unit that should be passed to a word.documents.contentcontrols to update the text in the word document based on the change in the actual data.
Dim NetworkLocation As String
NetworkLocation = "\\myServer\myFolder\mySubfolder\"
Dim CATS As String
CATS = "kittens.xlsx"
Excel.Application.Workbooks.Open FileName:=(NetworkLocation & "Other Subforder\ThisWway\" & CATS)
Dim DOGS As String
DOGS = "puppies.xlsx"
Excel.Application.Workbooks.Open FileName:=(NetworkLocation & "differentSubfolder\ThatWay\" & DOGS)
'Populates the array with analysis tables
Dim Temples As Object
Dim Template(3 To 9) As Variant
Template(3) = "\3\EVAL Table 3.xlsx"
Template(4) = "\4\EVAL Table 4.xlsx"
Template(5) = "\5\EVAL Table 5.xlsx"
Template(6) = "\6\EVAL Table 6.xlsx"
Template(7) = "\7\EVAL Table 7.xlsx"
Template(8) = "\8\EVAL Table 8.xlsx"
Template(9) = "\9\EVAL Table 9.xlsx"
Dim strXLname As String
Dim opener As Variant
For Each opener In Template
strXLname = NetworkLocation & "Other Subfolder\EVAL Tables\WonderPets" & opener
Excel.Application.Workbooks.Open FileName:=strXLname
Dim currentDiffernce As Long
currentDifference = ActiveSheet.Cells(5, 6).Value
'This code cycles through the different EVAL Table templates
ActiveSheet.Cells(1, 1).Value = CATS
ActiveSheet.Cells(2, 1).Value = DOGS
Dim k As Variant
For Each k In Tabs
controlThis = k & "-" & eval 'passes a string to the wdApp.contentcontrol
ActiveSheet.Rows.Hidden = False
ActiveSheet.Cells(1, 4).Value = k 'initialize k
ActiveSheet.Calculate
DoEvents
currentDifference = ActiveSheet.Cells(5, 6).Value 'stop blank tables from being produced using the total delta in the preprogrammed spreadsheet
If currentDifference = 0 Then 'since the total difference in the current analysis is 0 this bit of code skips to the next WonderPet
Else
controlThis = k & "-" & opener '(Was eval as variant used with thisTable array)passes a string to the wdApp.contentcontrol
Call PDFcrate 'Print the Table to a PDF file. Worked well and was made a subroutine.
Dim objWord As Object
Dim ws As Worksheet
'Dim cc As Word.Application.ContentControls
Set ws = ActiveWorkbook.Sheets("Sheet1")
Set objWord = CreateObject("Word.Application")
objWord.Visible = True
objWord.Documents.Open FileName:="myFilePath\Myfile.docx", noencodingdialog:=True ' change as needed
With objWord.ActiveDocument
.ContentControls(controlThis & " cats").Range.Text = eval.ActiveSheet.Cells(5, 4) 'These are the updates to the report for each content control with the title. Substituting SelectContentControlsByTitle() gives RTE-424 'Object Required'
.ContentControls(controlThis & " dogs").Range.Text = eval.ActiveSheet.Cells(5, 5)
.ContentControls(controlThis & " pets").Range.Text = eval.ActiveSheet.Cells(5, 6)
.ContentControls(controlThis & " Table).range. = 'Need to add the PDF to the report, perhaps using an RichTextConentConrols...additional suggestions welcomed (haven't researched it yet).
End With
Set objWord = Nothing
Word.Application.Documents.Close SaveChanges:=True 'Saves and Closes the document
Word.Application.Quit 'quits MS Word
End If
Next 'repeats for each tab with name "k" in the workbooks
Excel.Application.Workbooks(strXLname).Close
Next 'repeat for each evalTable
Excel.Application.Workbooks(CATS).Close
Excel.Application.Workbooks(DOGS).Close
End Sub
Word's content controls can't be picked up using a string as the index value the way other things can. The following line from the code sample in the question can't work:
.ContentControls(controlThis & " cats").Range.Text = eval.ActiveSheet.Cells(5, 4)
The only valid index value for a ContentControl is ID, which is a long number (GUID) assigned by the Word application when a ContentControl is generated.
The reason for this is that more than one content control can have the same Title (name) and/or Tag. Since this information is not unique it can't be used to pick up a single content control.
Instead, code needs to use either Document.SelectContentControlsByTitle or Document.SelectContentControlsByTag. These return an collection of content controls that meet the specified criterium. For example:
Dim cc as Word.ContentControls ' As Object if late-binding is used
With objWord.ActiveDocument
Set cc = .SelectContentControlsByTitle(controlThis & " cats")
'Now loop all the content controls in the collection to work with individual ones
End With
If it's certain there's only one content control with the Title, or only the first one is wanted, then it's possible to do this:
Dim cc as Word.ContentControl ' As Object if late-binding is used
With objWord.ActiveDocument
Set cc = .SelectContentControlsByTitle(controlThis & " cats").Item(1)
cc.Range.Text = eval.ActiveSheet.Cells(5, 4)
End With
Tip 1: Using ActiveDocument is not considered good practice for Word. As with ActiveCell (or anything else) in Excel, it's not certain that the "active" thing is the one that should be manipulated. More reliable is to use an object, which in this case can be assigned directly to the document being opened. Based on the code in the question:
Dim wdDoc as Object 'Word.Document
Set wdDoc = objWord.Documents.Open(FileName:="myFilePath\Myfile.docx", noencodingdialog:=True)
With wdDoc 'instead of objWord.ActiveDocument
Tip 2: Since the code in the question targets multiple content controls, rather than declaring multiple content control objects it might be more efficient to put the titles and values in an array and loop that.
This fixed it... looping through may have been the thing that got me unstuck.
The use of the plural ContentControls or singular ContentControl didn't seem to matter. My next trick is to get the tables into the word document... any thoughts?
Set wdDoc = Word.Application.Documents(wdDocReport)
Dim evalData(0 To 2) As Variant
evalData(0) = " CATS"
evalData(1) = " DOGS"
evalData(2) = " PETS"
Dim j As Variant
Dim i As Integer
i = 4
For Each j In evalData
Dim cc As Word.ContentControls
With Word.Application.Documents(wdDocReport)
.SelectContentControlsByTitle(controlThis & j).Item (1).Range.Text = ActiveWorkbook.ActiveSheet.Cells(5, i).Value
i = i + 1
End With
Next
Word.Application.Documents.Close SaveChanges:= True
Word.Application.Quit
Only one worksheet ever takes focus so the ActiveWorkbook and ActiveWorksheet didn't hurt me here

Transferring data from excel to MS word

I need a VBA code to update my word file. It which consists of some tables That has to be updated from excel file. Excel file consists of bearing data with different bearing numbers. And my report has to be updated with the bearing values. Like for my next report if I just enter the different bearing file it must read all the bearing data from that file.
This has to be done in 3 steps. I have attached a sample image. firstly identify the bearing name which is always in A column (In this case I need to find (248_R), 38,7 % ). Then select 6*6 matrix data (suppose I find the bearing data to be in A946 then I need to record data from B950 to G955) and then transfer to word file(Only the values to the table). I am a newbee in VBA coding please can someone help?
image of sample bearing name with matrix underneath
Image of what the tables look like in the word document:
The first part of copying the range you want is relatively easy. You can use the following code to copy your desired matrix. I am not sure about pasting to a word document yet, give me some more time on that.
(For now, if you run this macro, the range you want will be copied. You can then switch to your word document and hit Ctrl+V to paste it into the desired table.
Also, please check and see whether the following references have been added:
Option Explicit
Sub findBearingDataAndPasteToWord()
Dim i As Integer
Dim aCell As Range, rng As Range
Dim SearchString As String
Set rng = Range("A750:A1790")
SearchString = "(248_R), 38,7 %"
For Each aCell In rng
If InStr(1, aCell.Value, SearchString, vbTextCompare) Then
ActiveSheet.Range(Cells(aCell.row + 4, 1), Cells(aCell.row + 9, 6)).Copy
Dim wrdApp As Word.Application
Dim docWd As Word.Document
MsgBox "Please select the word document that you want to paste the copied table data into (after pressing OK)" & _
vbNewLine & vbNewLine & "Script written by takanuva15 with help from Stack Overflow"
docFilename = Application.GetOpenFilename()
If docFilename = "False" Then Exit Sub
Set docWd = getDocument(docFilename)
Set wrdApp = docWd.Application
wrdApp.Selection.EndKey Unit:=wdStory
wrdApp.Selection.TypeParagraph
wrdApp.Selection.TypeParagraph
wrdApp.Selection.PasteExcelTable False, True, False
Exit Sub
Else: End If
Next aCell
End Sub
'Returns the document with the given filename
'If the document is already open, then it returns that document
Public Function getDocument(ByVal fullName As String) As Word.Document
On Error Resume Next
Set wrdApp = GetObject(, "Word.Application")
If wrdApp Is Nothing Then Set wrdApp = CreateObject("Word.Application")
wrdApp.Visible = True
Dim fileName As String
Dim docReturn As Word.Document
fileName = Dir(fullName)
Set docReturn = Word.Documents(fileName)
If docReturn Is Nothing Then
Set docReturn = Word.Documents.Open(fullName)
End If
On Error GoTo 0
Set getDocument = docReturn
End Function

Excel VBA Import Word table with merged cells to Excel

I have many tables in a Word document (.docx) and I want to import them to a blank Excel sheet in an easy way. The tables in the Word document are not the same size (rows) and some rows have merged cells.
My code is below. I can choose the .docx and then select the number of the table to import but I only can import the headers, so I do not know if works fine. I am doing this because I want to keep the tables format (same rows) and is not valid if I use copy/paste.
When I run this code I get an error:
Run-time error '5941'. The requested member of the collection does not exist.
On this line:
Cells(iRow, iCol) = WorksheetFunction.Clean(.cell(iRow, iCol).Range.Text)
This is the code:
Sub ImportWordTable()
Dim wdDoc As Object
Dim wdFileName As Variant
Dim TableNo As Integer 'table number in Word
Dim iRow As Long 'row index in Excel
Dim iCol As Integer 'column index in Excel
wdFileName = Application.GetOpenFilename("Word files (*.docx),*.doc", , _
"Browse for file containing table to be imported")
If wdFileName = False Then Exit Sub '(user cancelled import file browser)
Set wdDoc = GetObject(wdFileName) 'open Word file
With wdDoc
TableNo = wdDoc.tables.Count
If TableNo = 0 Then
MsgBox "This document contains no tables", _
vbExclamation, "Import Word Table"
ElseIf TableNo > 1 Then
TableNo = InputBox("This Word document contains " & TableNo & " tables." & vbCrLf & _
"Enter table number of table to import", "Import Word Table", "1")
End If
With .tables(TableNo)
'copy cell contents from Word table cells to Excel cells
For iRow = 1 To .Rows.Count
For iCol = 1 To .Columns.Count
Cells(iRow, iCol) = WorksheetFunction.Clean(.cell(iRow, iCol).Range.Text)
Next iCol
Next iRow
End With
End With
Set wdDoc = Nothing
End Sub
The format of my tables is the following:
<header> Same number of rows for all
6 rows with 2 columns
</header>
<content of the table>
<header1>3 columns combined<header1>
multiple rows with 3 columns
<header1>3 columns combined<header1>
multiple rows with 3 columns
</content of the table>
Is something like this:
_______________________
|_________|____________|
|_________|____________|
|_________|____________|
|_________|____________|
|_________|____________|
|_________|____________|
|______________________|
|_____|__________|_____|
|_____|__________|_____|
|_____|__________|_____|
|_____|__________|_____|
|_____|__________|_____|
|______________________|
|_____|__________|_____|
|_____|__________|_____|
|_____|__________|_____|
|_____|__________|_____|
|_____|__________|_____|
Sorry for the table format but I do not know how to explain it better. The final goal is to leave it in excel as follows:
_______________________
|_________|____________|
|_________|____________|
|_________|____________|
|_________|____________|
|_________|____________|
|_________|____________|
|______________________||______________________|
|_____|__________|_____||_____|__________|_____|
|_____|__________|_____||_____|__________|_____|
|_____|__________|_____||_____|__________|_____|
|_____|__________|_____||_____|__________|_____|
|_____|__________|_____||_____|__________|_____|
|_____|__________|_____||_____|__________|_____|
|_____|__________|_____||_____|__________|_____|
|_____|__________|_____||_____|__________|_____|
|_____|__________|_____||_____|__________|_____|
|_____|__________|_____||_____|__________|_____|
How can I split the merged cells before insert in Excel? The steps would be to detect one by one as now the cells and when only found 1 split the cell or use as one
The error is caused because you cannot iterate through the cells of a table with merged cells by using SomeTable.Rows.Count and SomeTable.Columns.Count as 'grid references'.
This is because once you have horizontally merged one or more cells in a row, then the column count for that row decreases by n-1 where n is the number of merged cells.
So in your example table the column count is 3 but there is no column 3 in the first row hence the error.
You can use the Next method of the object returned by the Cell method on a Table object to iterate through the cell collection of the table. For each cell you can get the column and row indices and map them to Excel. However, for merged cells, you cannot get a column span property for each cell leaving you to need to look at Width properties to try and infer which cells are merged and by how much. In fact, it is going to be very difficult to recreate a Word table in an Excel worksheet where the table has lots of different cell widths and merging going on.
Here is an example of how to use the Next method:
Option Explicit
Sub Test()
Dim rng As Range
Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1")
CopyTableFromDocx "D:\test.docx", rng
End Sub
Sub CopyTableFromDocx(strMSWordFileName As String, rngTarget As Range)
Dim objDoc As Object
Dim lngTableIndex As Long
Dim objTable As Object
Dim objTableCell As Object
Dim lngRowIndex As Long, lngColumnIndex As Long
Dim strCleanCellValue As String
On Error GoTo CleanUp
'get reference to word doc
Set objDoc = GetObject(strMSWordFileName)
'handle multiple tables
Select Case objDoc.Tables.Count
Case 0
MsgBox "No tables"
GoTo CleanUp
Case 1
lngTableIndex = 1
Case Is > 1
lngTableIndex = InputBox("Which table?")
End Select
'clear target range in Excel
rngTarget.CurrentRegion.ClearContents
'set reference to source table
Set objTable = objDoc.Tables(lngTableIndex)
'iterate cells
Set objTableCell = objTable.Cell(1, 1)
Do
'get address of cell
lngRowIndex = objTableCell.Row.Index
lngColumnIndex = objTableCell.ColumnIndex
'copy clean cell value to corresponding offset from target range
strCleanCellValue = objTableCell.Range.Text
strCleanCellValue = WorksheetFunction.Clean(strCleanCellValue)
rngTarget.Offset(lngRowIndex - 1, lngColumnIndex - 1).Value = strCleanCellValue
Set objTableCell = objTableCell.Next
Loop Until objTableCell Is Nothing
'success
Debug.Print "Successfully copied table from " & strMSWordFileName
CleanUp:
If Err.Number <> 0 Then
Debug.Print Err.Number & " " & Err.Description
Err.Clear
End If
Set objDoc = Nothing
End Sub
Which can import this table:
Like so, into a worksheet:
Note there is no unambiguous way AFAIK to solve the challenge around how to know that Bar3 should span merge Excel columns, or that we want Baz3 to be in cell D3, not C3.
This is how I did it, I used the select command to select the table in word, and then pasted it into excel.
This will paste merged cells and all. From there, you can use the merge info in excel if you need to manipulate it further, clean the formatting or whatever else you need to do.
This example copies all tables out of a word doc into a new sheet for each table to the worksheet.
Sub CopyWordTables()
Dim wdDoc As Word.Document
Dim wdFileName As Variant
wdFileName = Application.GetOpenFilename("Word files (*.docx),*.docx", , _
"Browse for word documents")
If wdFileName = False Then
Exit Sub
End If
Set wdDoc = GetObject(wdFileName)
If wdDoc.Tables.Count = 0 Then
MsgBox "There are no tables in the selected document."
Exit Sub
End If
Dim intTableCount As Integer
intTableCount = 1
For Each Table In wdDoc.Tables
Table.Select
wdDoc.Application.Selection.Copy
Set Sheet = Sheets.Add(After:=ActiveSheet)
Sheet.Name = "Table " & intTableCount
intTableCount = intTableCount + 1
Sheet.Select
ActiveSheet.Paste
Next
Set wdDoc = Nothing
End Sub

VBA - Range Object Sets Only Once in Loop

I am writing code which matches a date (from a file), puts this into a collection and then attempts to find this on a spreadsheet. Once it finds it, it puts the following two items in the collection in the two cells. When I run this I get the following error: "Object variable or With block variable not set". I have attempted to debug my code and it shows that after the first loop of the code below, the range object, "rthecell", changes to the proper value. Once the second iteration of the loop occurs the value of "rthecell" changes to "Nothing".
Ex:
Set rtheCell = Range("A:A").Find(What:=LineItem1)
rtheCell.Offset(, 1).Value = LineItem3
rtheCell.Offset(, 2).Value = LineItem2
Set rtheCell = Nothing
Again, everything works as intended on the first iteration of the loop but I receive the error once the second iteration occurs.
Here is the full code:
Sub InputData()
'Declare variables
Dim sFilePath As String
Dim sLineFromFile As String
Dim saLineItems() As String
Dim element As Variant
Dim col As Collection
Dim LineItem1 As String
Dim LineItem2 As String
Dim LineItem3 As String
Dim rtheCell As Range
Set col = New Collection
'Insert file path name here, this file will be overwritten each morning
sFilePath = "P:\Billing_Count.csv"
Open sFilePath For Input As #1
Do Until EOF(1)
Line Input #1, sLineFromFile
'Split each line into a string array
'First replace all space with comma, then replace all double comma with single comma
'Replace all commas with space
'Then perform split with all values separated by one space
sLineFromFile = Replace(sLineFromFile, Chr(32), ",")
sLineFromFile = Replace(sLineFromFile, ",,", ",")
sLineFromFile = Replace(sLineFromFile, ",", " ")
saLineItems = Split(sLineFromFile, " ")
'Add line from saLineItem array to a collection
For Each element In saLineItems
If element <> " " Then
col.Add element
End If
Next
Loop
Close #1
'Place each value of array into a smaller array of size 3
Dim i As Integer
i = 1
Do Until i > col.Count
'Place each value of array into a string-type variable
'This line is the date
LineItem1 = col.Item(i)
i = i + 1
'This line should be the BW count make sure to check
LineItem2 = col.Item(i)
i = i + 1
'This line should be the ECC count make sure to check
LineItem3 = col.Item(i)
i = i + 1
'Find the matching date in existing Daily Billing File (dates on Excel must be formatted as
'general or text) and add ECC and BW counts on adjacent fields
Set rtheCell = Range("A3:A37").Find(What:=LineItem1)
rtheCell.Offset(, 1).Value = LineItem3 'This is LineItem3 since we can ECC data to appear before BW
rtheCell.Offset(, 2).Value = LineItem2
Set rtheCell = Nothing
LineItem1 = 0
Loop
'Format cells to appear as number with no decimals
'Format cells to have horizontal alignment
Sheets(1).Range("B3:C50").NumberFormat = "0"
Sheets(1).Range("C3:C50").HorizontalAlignment = xlRight
End Sub
when you use the Range.Find method, typically you would either use the After:= parameter in subsequent calls or use the Range.FindNext method which assumes After:= the last found item. Since you are not modifying the actual found cells' value(s) in any way, you need to record the original found cell (typically the address) because eventually you will loop back to the original.
dim fndrng as range, fndstr as string
set fndrng = Range("A:A").Find(What:=LineItem1, after:=cells(rows.count, "A"))
if not fndrng is nothing then
fndstr = fndrng.address
do while True
'do stuff here
set fndrng = Range("A:A").FindNext(after:=fndrng)
if fndstr = fndrng.address then exit do
loop
end if
That should give you the idea of looping through all the matching calls until you loop back to the original. tbh, it is hard to adequately expand on the small amount of code supplied.