# Word VBA Cell Selection Problem



## gijimbo (Mar 22, 2011)

I have a word document in which I'm trying to select the first cell of the last row of a table.  I keep getting an error (red circle with white 'X') that has no text.






Here's my code:

```
Sub IncrementTable()
ActiveDocument.Unprotect
Selection.Find.ClearFormatting
    With Selection.Find
        .Text = "REV."
        .Replacement.Text = ""
        .Forward = True
        .Wrap = wdFindContinue
        .Format = False
        .MatchCase = True
        .MatchWholeWord = True
        .MatchWildcards = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
    End With
    Selection.Find.Execute
    Selection.MoveDown Unit:=wdLine, Count:=1
    Selection.Rows.Delete
    
    ActiveDocument.Tables(4).Rows.Add
    
    MsgBox ("Last row in table 4 = " & ActiveDocument.Tables(4).Rows.Count & vbNewLine & _
            "Last row (alternate) = " & Selection.Information(wdMaximumNumberOfRows))
    
    Dim lastrow As Long
    lastrow = ActiveDocument.Tables(4).Rows.Count
    'Selection.Tables(4).Cell(lastrow, 1).Select
    
    'Selection.MoveDown Unit:=wdLine, Count:=12
    For i = 1 To 7
        Selection.Tables(4).Rows(lastrow).Select
        Selection.Collapse
        Set ffield = Selection.FormFields.Add( _
            Range:=Selection.Range, _
            Type:=wdFieldFormTextInput)
        ffield.Name = ""
        Selection.MoveRight Unit:=wdCell, Count:=1
    Next i
ActiveDocument.Protect Type:=wdAllowOnlyFormFields, NoReset:=True
End Sub
```

The error is occurring at the "Selection.Tables(4).Rows(lastrow).Select" line but as you can see from the commented areas, I've tried it in other places too with the same results.

Any ideas what I'm doing wrong?


----------



## gijimbo (Mar 22, 2011)

Sorry for the double post, I couldn't edit anymore.

The problem was that I needed ActiveDocument instead of Selection in front of .Tables(4)

Now that the macro was able to go further though, I've run into another error.





This one popped up after processing the line:
ffield.Name = ""

Any thoughts here?


----------



## Macropod (Mar 23, 2011)

Hi gijimbo,

For whatever reason, Word won't allow you to clear the formfield name. You could assign your own name to it, though.

From reading your code, it think it could also be made to work better:

```
Sub IncrementTable()
Dim iTbl As Integer, lastrow As Integer, i As Integer, j As Integer, ffield As FormField
With ActiveDocument
  iTbl = 4
  If .ProtectionType = wdAllowOnlyFormFields Then .Unprotect
  With .Tables(iTbl).Range
    With .Find
      .ClearFormatting
      .Text = "REV."
      .Replacement.Text = ""
      .Forward = True
      .Wrap = wdFindStop
      .Format = False
      .MatchCase = True
      .MatchWholeWord = True
      .MatchWildcards = False
      .MatchSoundsLike = False
      .MatchAllWordForms = False
      .Execute
    End With
    If .Find.Found Then .Rows.Last.Next.Delete
    .Rows.Add
    lastrow = .Information(wdMaximumNumberOfRows)
    MsgBox ("Last row in table 4 = " & lastrow)
  End With
  j = .FormFields.Count
  For i = 1 To 7
        Set ffield = .FormFields.Add(Range:=.Tables(iTbl).Rows(lastrow).Cells(i).Range, Type:=wdFieldFormTextInput)
        ffield.Name = "MyName" & j + i
  Next i
  .Protect Type:=wdAllowOnlyFormFields, NoReset:=True
End With
End Sub
```


----------



## gijimbo (Mar 23, 2011)

I had tried giving the fields an incrementing name (like in your example) but got the same error right after naming the first field (just like when I try to clear it).  

Also, this macro can run quite a few times (indefinitely really).  This means [ ffield.Name = "MyName" & j + i ] will start making duplicate names for the fields in each new row since j counts the total # of fields which is always the same.

Now here's the weird thing: on the actual document I can go to any field's properties (even the new ones) and delete the name/bookmark.  Word seems to have no problem with this when I do it manually. 

Really though, I'm not going to worry about the field names anymore.  The only reason I was trying to clear the names was because it was causing a "visual inconsistency".  I have 2007 and have the option turned on to display brackets "[    ]" around bookmarks (named fields).  The fields that were already there that didn't have names were not showing the brackets but of course the newly created ones (with default names) were showing them.  This really has no effect on the functionality of the documents based on this template so I just turned the display brackets option off so it wouldn't bother me anymore.

The OP code was my first stab at fixing/optimizing someone else's broken code so it was by no means my best optimized work.  When fixing code, I generally like to get it working before I optimize.  Thanks for your optimizing suggestions though, I'll make sure to throw'em in.  On that same note (if you were at all interested) I also removed the find function all together because:
1) It always finds the first cell of table 4
2) The second row of table 4 is always the one to be deleted


----------



## gijimbo (Mar 23, 2011)

Sorry for the double post again.

I'm having another issue.

Here is the code as is currently:

```
Option Explicit

Sub IncrementTable()

Dim i As Integer, _
    ffield As FormField
    
With ActiveDocument
    If .ProtectionType = wdAllowOnlyFormFields Then .Unprotect
    .Tables(4).Rows(2).Delete
    .Tables(4).Rows.Add
    For i = 1 To 7
        Set ffield = .FormFields.Add( _
            Range:=.Tables(4).Rows(.Tables(4).Rows.Count).Cells(i).Range, _
            Type:=wdFieldFormTextInput)
        If i = 4 Then
            ffield.TextInput.EditType _
                Type:=wdDateText, _
                Format:="MM/dd/yyyy"
        End If
    Next i
    .Protect _
        Type:=wdAllowOnlyFormFields, _
        NoReset:=True
End With
End Sub
```

I'm trying to make the field in the 4th column format as a date in the format "MM/dd/yyyy".  I can put stops in the code and follow it through and it appears to have no trouble doing anything.  However, when I try typing a date such as 1/1/11, nothing happens.  When I unprotect and check the properties, it still says the Type is "Regular Text" so it is not changing the type to Date and it's not keeping the MM/dd/yyyy.

When I manually record the operation I get this:

```
Sub Macro2()
'
' Macro2 Macro
'
'
    With Selection.FormFields(1)
        .Name = "Text240"
        .EntryMacro = ""
        .ExitMacro = ""
        .Enabled = True
        .OwnHelp = False
        .HelpText = ""
        .OwnStatus = False
        .StatusText = ""
        With .TextInput
            .EditType Type:=wdDateText, Default:="", Format:="MM/dd/yyyy"
            .Width = 0
        End With
    End With
End Sub
```

If I run the recorded macro, it works.

I trimmed it down to the below and it still works, so I'm kind of confused as to why it doesn't work with ffield which is a FormField variable.

```
Sub Macro1()
    Selection.FormFields(1).TextInput.EditType _
        Type:=wdDateText, _
        Format:="MM/dd/yyyy"
End Sub
```

Edit: I even tried this and it still worked...

```
Sub Macro1()
    Dim ffield As FormField
    
    Set ffield = Selection.FormFields(1)
    ffield.TextInput.EditType _
        Type:=wdDateText, _
        Format:="MM/dd/yyyy"
End Sub
```


----------



## Macropod (Mar 23, 2011)

Hi ,

With your IncrementTable code, what was being given the date format was the 1st cell, not the 4th.

Try:

```
Sub IncrementTable()
Dim i As Integer
With ActiveDocument
  If .ProtectionType = wdAllowOnlyFormFields Then .Unprotect
  With .Tables(4)
    .Rows(2).Delete
    .Rows.Add
    For i = 1 To 7
      .Range.FormFields.Add Range:=.Rows.Last.Cells(i).Range, _
        Type:=wdFieldFormTextInput
      If i = 4 Then _
        .Rows.Last.Cells(i).Range.FormFields(1).TextInput.EditType _
          Type:=wdDateText, Default:="", Format:="MM/dd/yyyy"
    Next i
  End With
  .Protect Type:=wdAllowOnlyFormFields, NoReset:=True
End With
End Sub
```

PS: I'm curious as to why it's considered necessary to delete the 2nd row, then add a new one. If the table only has two rows, why not simply re-set its formfields or clear its contents and add new formfields?

PPS: with the 'ffield.Name = "MyName" & j + i' in my previous post, you shouldn't get duplicate formfields, as the j sets the starting value to the count of all formfields already in the document and the i makes sure to increment each new formfield's counter. Even if the deleted row had formfields on it beforehand, having deleted them you can re-use their indices.


----------



## gijimbo (Mar 24, 2011)

Thanks so much again, for helping me out!  Just to make sure I understand why it wasn't working, please let me know if my following explanation is incorrect.

ffield only stores a *reference* to the *first* field created even though the line "_Set ffield = .FormFields.Add( ..._" gets run 7 times (creating 7 fields).  
This is because "Set" is used to initialize a reference and does not allow that reference to be changed?  

Although I go into further explanation below I think the simplest answer to both your PS and PPS is that the table has more than 2 rows (15 actually).



Macropod said:


> PS: I'm curious as to why it's considered necessary to delete the 2nd row, then add a new one. If the table only has two rows, why not simply re-set its formfields or clear its contents and add new formfields?



The document is a coversheet for a controlled set of documents.  
The table generally has 15 rows.  The first is the header row and the rest are for revision history.  Each time there is a revision, a brief overview of it's changes are recorded on the next open line in this table.  The whole document set is then printed and saved/filed away.  However, when there have been enough revisions, the coversheet begins to span across 2 pages.  Because there is a printed version for each of the changes it's not hugely important to keep every change on the cover sheet (since it's mainly a reference of the past few changes).  To prevent the coversheet from spanning 2 pages unnecessarily, this macro simply deletes the oldest change overview from the top of the list, shifting the list up, then opens up a new free slot at the bottom for the next revision.  



Macropod said:


> PPS: with the 'ffield.Name = "MyName" & j + i' in my previous post, you shouldn't get duplicate formfields, as the j sets the starting value to the count of all formfields already in the document and the i makes sure to increment each new formfield's counter. Even if the deleted row had formfields on it beforehand, having deleted them you can re-use their indices.



Since you now know that I have more than 2 rows and that the deleted row is not the last row, I'm sure you understand why I would be getting duplicate field names.

When the second row gets deleted, the rest (including the last one made by this macro) get shifted down but maintain the same names, then when a new row is created all of its fields get the same names as ones in the previous new row.


----------



## gijimbo (Mar 24, 2011)

Just cleaned it up a tiny bit from what you had but thought I would post anyways (for anyone looking at this thread in the future).
Changed 
"_.Rows.Last.Cells(i).Range.FormFields(1).TextInput.EditType_" 
to
"_.Rows.Last.Range.FormFields(i).TextInput.EditType_"

Thanks again!

Here's the final product:

```
Sub IncrementTable()

'Delcare varaiables
Dim i As Integer
    
With ActiveDocument
    'Remove protection if protected
    If .ProtectionType = wdAllowOnlyFormFields Then .Unprotect
    With .Tables(4)
        'Delete oldest rev
        .Rows(2).Delete
        'Add new row on bottom
        .Rows.Add
        For i = 1 To 7
            'Add a form field to each cell
            .Range.FormFields.Add _
                Range:=.Rows.Last.Cells(i).Range, _
                Type:=wdFieldFormTextInput
            'Format date cell (4th) as a date
            If i = 4 Then _
                .Rows.Last.Range.FormFields(i).TextInput.EditType _
                    Type:=wdDateText, _
                    Format:="MM/dd/yyyy"
        Next i
    End With
    'Re-protect
    .Protect _
        Type:=wdAllowOnlyFormFields, _
        NoReset:=True
End With
End Sub
```


----------



## Macropod (Mar 25, 2011)

Hi gijimbo,

Glad you got it sorted.

Thanks for the clarifications about the reason for the row deletion/creation and for the issues you foresaw with the 'ffield.Name = "MyName" & j + i' approach.

To eliminate the unwanted formfield bookmarks, insert:
ActiveDocument.Bookmarks(.Rows.Last.Range.FormFields(i).Name).Delete
before your 'Format date cell (4th) as a date' comment.


----------



## gijimbo (Mar 25, 2011)

Hey thanks! 
That provides the solution to the problem in the second post.  
I had to move the bookmark deletion after the date format change though.   Word was automatically reassigning a name to the field when the format was changed. 

Edit: I kind of hate it when programs do stuff like that.  I can understand initializing a field with a name, but if a field has no name that must mean it was intentionally removed.  If that's the case, then how would it be at all helpful to anyone in any circumstance to automatically add one back in???   Even if it was helpful in some circumstance (that eludes me), is that circumstance so likely and common that reassigning a bookmark should be the default?


----------



## gijimbo (Mar 22, 2011)

I have a word document in which I'm trying to select the first cell of the last row of a table.  I keep getting an error (red circle with white 'X') that has no text.






Here's my code:

```
Sub IncrementTable()
ActiveDocument.Unprotect
Selection.Find.ClearFormatting
    With Selection.Find
        .Text = "REV."
        .Replacement.Text = ""
        .Forward = True
        .Wrap = wdFindContinue
        .Format = False
        .MatchCase = True
        .MatchWholeWord = True
        .MatchWildcards = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
    End With
    Selection.Find.Execute
    Selection.MoveDown Unit:=wdLine, Count:=1
    Selection.Rows.Delete
    
    ActiveDocument.Tables(4).Rows.Add
    
    MsgBox ("Last row in table 4 = " & ActiveDocument.Tables(4).Rows.Count & vbNewLine & _
            "Last row (alternate) = " & Selection.Information(wdMaximumNumberOfRows))
    
    Dim lastrow As Long
    lastrow = ActiveDocument.Tables(4).Rows.Count
    'Selection.Tables(4).Cell(lastrow, 1).Select
    
    'Selection.MoveDown Unit:=wdLine, Count:=12
    For i = 1 To 7
        Selection.Tables(4).Rows(lastrow).Select
        Selection.Collapse
        Set ffield = Selection.FormFields.Add( _
            Range:=Selection.Range, _
            Type:=wdFieldFormTextInput)
        ffield.Name = ""
        Selection.MoveRight Unit:=wdCell, Count:=1
    Next i
ActiveDocument.Protect Type:=wdAllowOnlyFormFields, NoReset:=True
End Sub
```

The error is occurring at the "Selection.Tables(4).Rows(lastrow).Select" line but as you can see from the commented areas, I've tried it in other places too with the same results.

Any ideas what I'm doing wrong?


----------



## Macropod (Mar 25, 2011)

gijimbo said:


> Even if it was helpful in some circumstance (that eludes me), is that circumstance so likely and common that reassigning a bookmark should be the default?


I wouldn't have thought so either ...


----------

