Unwanted Insert Row Infinite Loop - excel

For some reason when i use the insert line code, it keeps on inserting a new row forever! I wrote the code that at the beginning there is a do while loop that goes through all the cells in column C, when it hits a cell in column C that is empty then an variable keeps the cell number.
and then i wrote another subroutine (which gets called when something changes on the spreadsheet) that if something is written in that empty cell in column C, then insert new row. but it just keeps on going forever!
The following code is under a module
Dim a, count As Integer
Sub check()
a = 0
count = 3
Do While a = 0
count = count + 1
If Range("C" & count).Value = "" Then
a = 1
End If
Loop
End Sub
Sub addrow()
If Range("C" & count).Value <> "" Then
Range("C" & count).Offset(1).EntireRow.Insert
count = count + 1
With Range("B" & count, "AL" & count)
.Borders(xlEdgeLeft).LineStyle = xlContinuous
.Borders(xlEdgeRight).LineStyle = xlContinuous
.Borders(xlEdgeBottom).LineStyle = xlContinuous
.Borders(xlEdgeTop).LineStyle = xlContinuous
.Borders(xlInsideVertical).LineStyle = xlContinuous
End With
End If
End Sub
And this code is under the worksheet
Private Sub Worksheet_Change(ByVal Target As Range)
addrow
End Sub
and subroutine "CHECK" is being called when the workbook is opened.
I have no idea why there is an infinite loop! please help.
Thank you

Just sandwich your Worksheet_Change event with Application.EnableEvents=False/True:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
addrow
Application.EnableEvents = True
End Sub
The reason is simple - when Worksheet_Change event inserts new row, it changes the content of the sheet, triggering Worksheet_Change event again. Worksheet_Change event insert new row again, and so on. Infinity loop:)
Btw, the best practice is to use error handling (it sets back Application.EnableEvents = True even if error occurs in addrow subroutine):
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo ErrorHandler
Application.EnableEvents = False
addrow
ExitHere:
Application.EnableEvents = True
Exit Sub
ErrorHandler:
Resume ExitHere
End Sub

Related

Delete entire based on another cell value

I need help with Excel VBA code.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 3 And Target.Cells.Count = 1 Then
If LCase(Target.Value) = "-1" Then
With Target.EntireRow.ClearContents
End With
End If
End If
If Target.Column = 3 And Target.Cells.Count = 1 Then
If LCase(Target.Value) = "1000" Then
With Target.EntireRow
.Copy Sheets("Week Schedule").Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
.Delete
End With
End If
End If
End Sub
If the third column we enter -1 it will clear the row. If we enter 1000 it will be copied to another sheet and deleted from the current sheet.
The above code is working fine. Instead of clearing row data, I want to delete that row.
So added
Line 4 With Target.EntireRow.ClearContents to With Target.EntireRow.Delete
But it shows an error.
It would help to know what error you get. Assuming the error is caused because the Week Schedule sheet does not exist, you can add a check for that. After that, your code works fine:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 3 And Target.Cells.Count = 1 Then
If LCase(Target.Value) = "-1" Then
With Target.EntireRow.ClearContents
End With
End If
End If
If Target.Column = 3 And Target.Cells.Count = 1 Then
If LCase(Target.Value) = "1000" Then
With Target.EntireRow
SheetExistsOrCreate ("Week Schedule")
.Copy Sheets("Week Schedule").Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
.Delete
End With
End If
End If
End Sub
Function SheetExistsOrCreate(name As Variant)
For i = 1 To Worksheets.Count
If Worksheets(i).name = "MySheet" Then
exists = True
End If
Next i
If Not exists Then
Worksheets.Add.name = name
End If
End Function
Please, try the next adapted code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 3 And Target.Cells.Count = 1 Then
Application.EnableEvents = False
If LCase(Target.Value) = -1 Then
Target.EntireRow.Delete
ElseIf Target.Value = 1000 Then
With Target.EntireRow
.Copy Sheets("Week Schedule").Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
.Delete
End With
End If
Application.EnableEvents = True
End If
End Sub
The above code assumes that the Target value means a number, not a string looking as a number. If a string, you can place them between double quotes, as in your initial code.
Of course, a sheet named "Week Schedule" must exist in the active workbook and must not be protected.

How to combine multiple worksheet Change events Excel VBA

I need to combine the following 3 subroutines into a single worksheet change event but I am unsure how.
I have tried writing one sub in the worksheet editor and another in the workbook editor. However given that I have 3 subroutines all referring to the same worksheet, I am unsure how to combine them. Any help is greatly appreciated!
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Range("D3:D100")) Is Nothing Then
Exit Sub
Else
Dim i As Integer
For i = 3 To 100
If Range("D" & i).Value = "Remote" Then
Range("O" & i).Value = "N/A"
Range("P" & i).Value = "N/A"
Range("Q" & i).Value = "N/A"
End If
Next i
End If
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target,Range("H3:H100")) Is Nothing Then
Exit Sub
Else
Dim e As Integer
For e = 3 To 100
If Range("H" & e).Value = 1 Then
Range("I" & e).Value = "N/A"
End If
Next e
End If
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target,Range("I3:I100")) Is Nothing Then
Exit Sub
Else
Dim e As Integer
For e = 3 To 100
If Range("I" & e).Value = 1 Then
Range("H" & e).Value = "N/A"
End If
Next e
End If
End Sub
Flip the logic.
If Intersect(Target, Range("D3:D100")) Is Nothing Then
Exit Sub
Else
...
End If
Change this to
If Not Intersect(Target, Range("D3:D100")) Is Nothing Then
' Remove Exit Sub
' Remove Else
...
End If
Do the same for the two other Intersect calls and then combine everything into one Worksheet_Change handler.
Most likely you want to disable events as well, to avoid re-triggering the event when writing to the sheet:
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo SafeExit
Application.EnableEvents = False
' Your three Intersect checks
SafeExit:
Application.EnableEvents = True
End Sub
try this. put this in the worksheet, not the workbook
Private Sub Worksheet_Change(ByVal Target As Range)
Dim c As Integer
If Not Intersect(Target, Range("D3:D100")) Is Nothing Then
c = 1
Else
If Not Intersect(Target, Range("H3:H100")) Is Nothing Then
c = 2
Else
If Not Intersect(Target, Range("I3:I100")) Is Nothing Then
c = 3
End If
End If
End If
Select Case c
Case 1
' your stuff
Case 2
'your stuff
Case 3
'your stuff
Case Else
End Select
End Sub

Avoid highlighting rows that are not intended to

I have the following code to highlight in green the row which the user clicks.
In the end of the code, I select the cell B6 to deselect the whole row and move the selection above.
It is working fine except for the fact that cell B6 is also being highlighted in green and I do not want that. How can I remove that?
In the worksheet I have:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'If not in the table, exit sub
If Intersect(Range("Schema"), ActiveCell.EntireRow) Is Nothing Then Exit Sub
Call ClickInside
End Sub
And in the module:
Sub ClickInside()
Dim cellno As String: cellno = Str(ActiveCell.row)
Dim myRow As Range
Set myRow = ActiveCell.EntireRow 'I want to select the row in the table ONLY
Call Unprotect_table
Call MarkRow(cellno, myRow)
Call Protect_table
End Sub
Sub MarkRow(cellno As String, myRow As Range)
'Marking that row in green
Range("Schema").Interior.ColorIndex = 0
Range("B" & Trim(cellno) & ":I" & Trim(cellno)).Select
With Selection.Interior
.PatternColorIndex = xlAutomatic
.Color = RGB(0, 255, 0)
.TintAndShade = 0
.PatternTintAndShade = 0
End With
Application.ScreenUpdating = False
'Show above
If Not myRow Is Nothing And CLng(cellno) >= 9 Then
Range("EditCountry").Value2 = ThisWorkbook.ActiveSheet.Range("B" & Trim(cellno)).Value2
Range("EditNodeName").Value2 = ThisWorkbook.ActiveSheet.Range("C" & Trim(cellno)).Value2
Range("EditNodeId").Value = ThisWorkbook.ActiveSheet.Range("D" & Trim(cellno)).Value2
Range("EditParentNode").Value = ThisWorkbook.ActiveSheet.Range("E" & Trim(cellno)).Value2
Range("EditParentNodeId").Value = ThisWorkbook.ActiveSheet.Range("F" & Trim(cellno)).Value2
Range("EditActive").Value = ThisWorkbook.ActiveSheet.Range("G" & Trim(cellno)).Value2
Range("EditFrom").Value = ThisWorkbook.ActiveSheet.Range("H" & Trim(cellno)).Value2
Range("EditTo").Value = ThisWorkbook.ActiveSheet.Range("I" & Trim(cellno)).Value2
End If
'Move selection
Range("B6").Select
End Sub
Thanks!
Your statement Range("B6").Select triggers the event-routine a second time. To prevent this, use the statement Application.EnableEvents = False:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Intersect(Range("Schema"), ActiveCell.EntireRow) Is Nothing Then Exit Sub
Application.EnableEvents = False
Call ClickInside
Application.EnableEvents = True
End Sub
However, maybe you could have a look to other solution that uses conditional formatting, for example https://stackoverflow.com/a/22350417/7599798

Clear the contents of columns B to F if cell A is empty

I have a worksheet with values depending on Cell A. If a row in column A contains a value then cells from Columns B through H will be changed accordingly.
If Cell of Column A is empty I want to reset the cells from columns D through F.
I wrote down the following VBA Code
Private Sub Worksheet_Change(ByVal Target As Range)
Dim n As Integer
For n = 5 To 75
Application.EnableEvents = False
If VarType(Cells(n, 1)) = vbEmpty Then
Cells(n, 4).ClearContents
Cells(n, 5).ClearContents
Cells(n, 6).ClearContents
Application.EnableEvents = True
End If
Next n
End Sub
The "FOR" Loop is annoying, and making the Excel to pause for 1 second or more after any entry to any Cell, can anyone help me correct the above code to do what I need to do without the "FOR" loop.
You are using a Worksheet_Change event and you iterating through 70 rows each time something changes.. this is a bad approach for this kind of problem and that's why there is a delay.
Instead, try
Private Sub Worksheet_Change(ByVal Target As Range)
Dim n As Long
If Target.Column = 1 Then
If IsEmpty(Cells(Target.Row, 1)) Then
Range("B" & Target.Row & ":F" & Target.Row).ClearContents
End If
End If
End Sub
this will only clear the cells if you remove a value from column A => when cell in column A is empty
Try this:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim i As Integer
If Mid(Target.Address(1, 1), 1, 2) = "$A" Then
If Target.Cells(1, 1).Value = "" Then
For i = 4 To 6
Target.Cells(1, i).Value = ""
Next i
End If
End If
End Sub
Give this a try:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rLook As Range, r As Range, Intr As Range
Set rLook = Range("A5:A75")
Set Intr = Intersect(rLook, Target)
If Intr Is Nothing Then Exit Sub
Application.EnableEvents = False
For Each r In Intr
If r.Value = "" Then
rw = r.Row
Range("D" & rw & ":F" & rw).ClearContents
End If
Next r
Application.EnableEvents = True
End Sub
It should have minimal impact on timing.
Use a range object.
The following line of code will print the address of the Range we'll use to clear the contents. The first cells call gets the upper left corner of the range, the second cells call gets the lower right corner of the range.
Private Sub test()
Debug.Print Range(Cells(5, 4), Cells(75, 6)).Address
End Sub
We apply this to your code like this:
Private Sub Worksheet_Change(ByVal Target As Range)
If VarType(Cells(Target.Row, 1)) = vbEmpty Then
Application.EnableEvents = False
Range(Cells(Target.Row, 4), Cells(Target.Row, 6)).ClearContents
Application.EnableEvents = True
End If
End Sub
One final sidenote: You should use an error handler to make sure events are always enabled when the sub exits, even if an error occurs.
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo ErrHandler
If VarType(Cells(Target.Row, 1)) = vbEmpty Then
Application.EnableEvents = False
Range(Cells(Target.Row, 4), Cells(Target.Row, 6)).ClearContents
End If
ExitSub:
Application.EnableEvents = True
Exit Sub
ErrHandler:
MsgBox "Oh Noes!", vbCritical
Resume ExitSub
End Sub
You should disable events and cater for multiple cells when using the Change event.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng1 As Range
Dim rng2 As Range
Set rng1 = Intersect(Columns("A"), Target)
If rng1 Is Nothing Then Exit Sub
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
For Each rng2 In rng1.Cells
If IsEmpty(rng2.Value) Then rng2.Offset(0, 1).Resize(1, 5).ClearContents
Next
With Application
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
For those that need to have data entered in one cell cleared (in a column) when there's a change in another column use this, which is a modification of Gary's Student.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rLook As Range, r As Range, Intr As Range
Set rLook = Range("D:D")
Set Intr = Intersect(rLook, Target)
If Intr Is Nothing Then Exit Sub
Application.EnableEvents = False
For Each r In Intr
If r.Value = "" Then
rw = r.Row
Range("L:L").ClearContents
End If
Next r
Application.EnableEvents = True
End Sub

How do I block/clear data for each cell in a column that matches the conditional if statement in VBA?

I am new to VBA programming in excel and would like to know how to do the following (I have searched google and will post what I have tried here with sample code).
Column G, starting at G11 continuing to the end of the sheet, contains 2 values: either "Full Time" or "Part Time".
In column S, starting at S11 continuing until the end of the sheet, our accountant will enter a Dollar value. The Accountant wants the excel cell in Column G to block/clear out any data and have a popup message saying that "You cannot edit this Cell in Column G as the employee is Part Time".
I used this code, but it only works for Row 11. I would like this to work for every row in Column G. Do you have any pointers or tips? Thanks in advance.
I use the 2 events Change and SelectionChange
Private Sub Worksheet_Change(ByVal Target As Range)
If [$G11] = "Part Time" Then
[$S11].Interior.ColorIndex = 34
[$S11].ClearContents
[$S11].Locked = True
Else
[$S11].Interior.ColorIndex = 12
[$S11].Locked = False
End If
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If [$G11] = "Part Time" Then
[$S11].ClearContents
[$S11].Locked = True
Else
[$S11].Locked = False
End If
End Sub
Try this out. I made some assumptions based on what you wrote, so if it doesn't quite fit your data, let me know.
Private Sub Worksheet_Change(ByVal Target As range)
If Not Intersect(Target, .Columns("S:S")) Is Nothing Then 'only do this if column S is changed
Application.EnableEvents = False
If range("G" & Target.Row) = "Part Time" Then
With range("S" & Target.Row)
.Interior.ColorIndex = 34
.ClearContents
.Locked = True
End With
Else
With range("S" & Target.Row)
.Interior.ColorIndex = 12
.Locked = False
End With
End If
Application.EnableEvents = True
End If
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As range)
If Not Intersect(Target, .Columns("S:S")) Is Nothing Then 'only do this if column S is changed
Application.EnableEvents = False
If range("G" & Target.Row) = "Part Time" Then
With range("S" & Target.Row)
.ClearContents
.Locked = True
End With
Else
range("S" & Target.Row).Locked = False
End If
Application.EnableEvents = True
End If
End Sub

Resources