VBA - copy & paste formula as a value as inserts row - excel

Excel 2016 - when the user enters "CRED" in column D require Excel to copy the entire row and insert on the next line.
The below code inserts the next line AOK including a new code of RECMER (Column D). In addition to this I need it to copy/paste the formula (Column C) as a value in the same column on the next line.
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo errHnd
'Don't do anything if more than one cell has been changed
If Target.Cells.Count > 1 Then Exit Sub
'Determine if the changed cell is in Column C and is a Y
If Target.Column = 4 Then
If Target = "CRED" Then
'Disable events so code doesn't fire again when row is inserted
Application.EnableEvents = False
'Copy & Insert changed Row, Clear dotted lines
Target.EntireRow.Copy
Range("A" & Target.Row + 1).Insert Shift:=xlDown
Application.CutCopyMode = False
'Put 2201 in Column B of inserted Row
Range("D" & Target.Row + 1) = "RECMER"
End If
End If
errHnd:
'Re-enable event
Application.EnableEvents = True
End Sub

Try the code below:
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo errHnd
'Don't do anything if more than one cell has been changed
If Target.Cells.Count > 1 Then Exit Sub
'Determine if the changed cell is in Column C and is a Y
If Target.Column = 4 Then
If Target = "CRED" Then
'Disable events so code doesn't fire again when row is inserted
Application.EnableEvents = False
'Copy & Insert changed Row, Clear dotted lines
Target.EntireRow.Copy
Range("A" & Target.Row + 1).Insert Shift:=xlDown
Application.CutCopyMode = False
'Put 2201 in Column B of inserted Row
Range("D" & Target.Row + 1) = "RECMER"
' ======= Added the 2 lines of code below =======
' copy >> paste special values only from Column C
Range("C" & Target.Row).Copy
Range("C" & Target.Row + 1).PasteSpecial xlPasteValues
End If
End If
errHnd:
'Re-enable event
Application.EnableEvents = True
End Sub

Related

Prevent EventChange Sub running unexpectedly

Advice would be gratefully appreciated. I am developing a spreadsheet using Excel 2016/Windows.
I have written 4 eventchange subroutines and all work well. The VBA Code for a worksheet checks for 4 events. Event 1, 2 and 3 enter today's date in a cell if data is entered in another cell (code not included below)
Code for EventChange works fine, but sometimes works when not expected to!
EventChange4 moves a value from one cell to another if another cell contains the text in Column J is "THIS Month – Payment Due" or "Issued But Not Paid. The second part of this eventchange4 moves a zero value to 2 cells if the data in column j contains text "not going ahead"
I am new to VBA. The problem is that eventchange4 runs for no apparent reason, e.g. copying a cell value in column H down to another cell in column h. How can I modify the code such that that eventchange4 only runs when the data in Column J Changes??? All advice gratefully accepted!!!!
Private Sub Worksheet_Change(ByVal Target As Range)
Call EventChange_1(Target)
Call EventChange_2(Target)
Call EventChange_3(Target)
Call EventChange_4(Target)
End Sub
Sub EventChange_1(ByVal Target As Range)
'Update on 11/11/2019 -If data changes in column L, insert
'today's date into column M
End Sub
Sub EventChange_2(ByVal Target As Range)
'Update on 15/01/2020 -If data changes in column P, insert today's date
'into next Column Q
End Sub
Sub EventChange_3(ByVal Target As Range)
'Update on 15/01/2020 -If data changes in column R, insert today's date
'into next Column S
End Sub
Sub EventChange_4(ByVal Target As Range)
On Error Resume Next
Application.EnableEvents = False
' this works !
If Target.Column = 10 And (Target.Value = "THIS Month – Payment Due" Or Target.Value = "Issued But Not Paid") Then
Range("K" & Target.Row).Value = Range("I" & Target.Row).Value
Range("I" & Target.Row).Clear
MsgBox "Moved Commission Due to Month Paid"
End If
If Target.Column = 10 And (Target.Value = "Not Going Ahead") Then
Range("I" & Target.Row).Value = 0
Range("K" & Target.Row).Value = 0
MsgBox "Moved ZERO to Initial Commisson and Month Paid"
End If
Application.EnableEvents = True
End Sub
Ideally you should update your code so it can properly handle a Target range which is not just a single cell:
Sub EventChange_4(ByVal Target As Range)
Dim rng As Range, c As Range, v
'any part of Target in Column J?
Set rng = Application.Intersect(Target, Me.Columns(10))
If Not rng Is Nothing Then
'have some cells to process...
On Error GoTo haveError
Application.EnableEvents = False
'process each affected cell in Col J
For Each c In rng.Cells
v = c.Value
If v = "THIS Month – Payment Due" Or v = "Issued But Not Paid" Then
Range("K" & c.Row).Value = Range("I" & c.Row).Value
Range("I" & c.Row).Clear
MsgBox "Moved Commission Due to Month Paid"
End If
If v = "Not Going Ahead" Then
Range("I" & c.Row).Value = 0
Range("K" & c.Row).Value = 0
MsgBox "Moved ZERO to Initial Commisson and Month Paid"
End If
Next c
End If
haveError:
Application.EnableEvents = True
End Sub
NOTE: this is assumed to be in the relevant worksheet code module - otherwise you should qualify the Range() calls with a specific worksheet reference.
All your "change" handlers should follow a similar pattern.
Tim apologies. I am new to this and was anxious to get a solution. Thank you for your response. Advice Noted. T
When I attempt to insert or delete a row in the spreadsheet, the VBA code identifies a worksheet event and attempts to run the code. The spreadsheet crashes. I have attempted to add code that will prevent this by checking at the beginning of the module if a row has been inserted or deleted before the other worksheet change event if statements are checked
Thank you
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim aCell As Range
Dim wsInc As Worksheet
Dim count As Integer
Dim lRow As Long
Dim ans As Variant
Dim tb As ListObject
On Error GoTo Whoa
Application.EnableEvents = False
Set tb = ActiveSheet.ListObjects(1)
MsgBox Target.Rows.count
If tb.Range.Cells.count > count Then
count = tb.Range.Cells.count
' GoTo Whoa
ElseIf tb.Range.Cells.count < count Then
count = tb.Range.Cells.count
' GoTo Whoa
'~~> Check if the change happened in Col A
ElseIf Not Intersect(Target, Columns(1)) Is Nothing Then
For Each aCell In Target.Cells
With aCell
If Len(Trim(.Value)) = 0 Then
.Offset(, 1).ClearContents
Else
.Offset(, 1).NumberFormat = "dd/mm/yyyy"
.Offset(, 1).Value = Now
With .Interior
.Pattern = xlNone
.TintAndShade = 0
.PatternTintAndShade = 0
End With
End If
End With
Next
'~~> Check if the change happened in Col L
ElseIf Not Intersect(Target, Columns(12)) Is Nothing Then
Set wsInc = Sheets("Income")
lRow = wsInc.Range("A" & wsInc.Rows.count).End(xlUp).Row + 1
For Each aCell In Target.Cells
With aCell
If Len(Trim(.Value)) = 0 Then
.Offset(, 1).ClearContents
Else
.Offset(, 1).NumberFormat = "dd/mm/yyyy"
.Offset(, 1).Value = Now
With .Interior
.Pattern = xlNone
.TintAndShade = 0
.PatternTintAndShade = 0
End With
'~~> Check of the value is Fees Received, Policy No. Issued
If .Value = "Fees Received" Or .Value = "Policy No. Issued" Then
ans = MsgBox("Do you want to copy this client to the Income Worksheet?", vbQuestion + vbYesNo)
If ans = False Then Exit For
wsInc.Range("A" & lRow).Value = Range("A" & aCell.Row).Value
End If
End If
End With
Next
End If
Letscontinue:
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume Letscontinue
End Sub

VBA code for moving completed rows to another sheet causes strange behavior

Disclaimer: I am not well-versed in VBA and have pieced together the following code by reading various blogs, etc.
My code "works" in that it moves rows whose status is changed to Done from the Active sheet to the Completed sheet. This was the point of the code.
The issue comes when I use the drag button (the little black corner thingy) to create another row on the source sheet (Active sheet). It for some reason copies the header row from the Active sheet to a new row on the Completed sheet.
It must be due to the copy and paste action, but I'm not sure how it's tied to dragging the table to create a row (if at all). Any help or guidance to this VBA amateur would be much appreciated.
Private Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
Application.EnableEvents = False
'If Cell that is edited is in column H and the value is Done
If Target.Column = 8 And Target.Value = "Done" Then
'Define last row on completed worksheet to know where to place the row of data
LrowCompleted = Sheets("Completed").Cells(Rows.Count, "B").End(xlUp).Row
'Copy and paste data
Range("B" & Target.Row & ":K" & Target.Row).Copy Sheets("Completed").Range("B" & LrowCompleted + 1)
'Delete Row from Project List
Range("B" & Target.Row & ":K" & Target.Row).Delete xlShiftUp
End If
Application.EnableEvents = True
End Sub
On Error Resume Next hides potential errors. For example, Target.Value = "Done" will throw an error if Target is a multi-cell range.
Perhaps try the following:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column <> 8 Then Exit Sub
If Target.CountLarge <> 1 Then Exit Sub
On Error GoTo SafeExit
Application.EnableEvents = False
If Target.Value = "Done" Then
Dim LrowCompleted as Long
LrowCompleted = Sheets("Completed").Cells(Rows.Count, "B").End(xlUp).Row
Me.Range("B" & Target.Row & ":K" & Target.Row).Copy ThisWorkbook.Sheets("Completed").Range("B" & LrowCompleted + 1)
Me.Range("B" & Target.Row & ":K" & Target.Row).Delete xlShiftUp
End If
SafeExit:
Application.EnableEvents = True
End Sub

delete entire row if cell G ="YES"

hi I have a code to delete entire row if cell in column G ="YES". It works fine, but when copy cells from one workbook to another it deletes the last row that is paste. Same as if I drag cell to auto fill.
Private Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
Application.EnableEvents = False
'If Cell that is edited is in column U and the value is completed then
If Target.Column = 7 And Target.Value = "YES" Then
'Define last row on completed worksheet to know where to place the row of data
LrowCompleted = Sheets("EQUIP. OFF RENT").Cells(Rows.Count, "A").End(xlUp).Row
'Copy and paste data
Range(Target.Row & ":" & Target.Row).Copy Sheets("EQUIP. OFF RENT").Range("A" & LrowCompleted + 1)
End If
If Target.Column = 7 And Target.Value = "YES" Then
Range(Target.Row & ":" & Target.Row).Delete
End If
Application.EnableEvents = True
After analyzing your code, it's a classical problem with the On Error Resume Next, combined with the Application.EnableEvents = False.
Even if there is an error in the code, the job is still running. That's why the last cell is deleted after a paste for example.
To avoid this, i simply erase the error resume next and the enableevents, and add this line before the first If statement :
If Target.Column = 1 Then Exit Sub
So please try this :
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 1 Then Exit Sub
If Target.Column = 7 And Target.Value = "YES" Then
'Define last row on completed worksheet to know where to place the row of data
LrowCompleted = Sheets("EQUIP. OFF RENT").Cells(Rows.Count, "A").End(xlUp).Row
'Copy and paste data
Range(Target.Row & ":" & Target.Row).Copy Sheets("EQUIP. OFF RENT").Range("A" & LrowCompleted + 1)
End If
If Target.Column = 7 And Target.Value = "YES" Then
Range(Target.Row & ":" & Target.Row).Delete
End If
End Sub

Setting Excel cell value based on another cell value using VBA

I have the following spreadsheet. When ever there is an x in cell B I need to populate the d and e cells in the same row using an equation I have.
if there is no x in the b cell I need to manually enter values into cells d & e.
How do I make my code non-row specific?
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim val As String
val = Range("B3").Value
If val = "x" Then
Range("E3").Value = Range("d2").Value * Range("G2").Value
Range("D3").Value = Range("D2").Value
End If
End Sub
I'm not sure if I understand correctly, but if you have a parameter: row = 3 you can use Range("E" & row) instead of Range("E3").
Put a loop around that where you vary 'row' for the rows you want to modify.
Hope that helps!
You've created a sub procedure around the Worksheet_SelectionChange event. In fact, you require Worksheet_Change and you need to,
disable event handling so you can write new values/formulas to the worksheet without running the Worksheet_Change on top of itself.
loop through each matching cell in Target to compensate for circumstances when Target can be more than a single cell,
add error control.
Rewrite:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("B:B")) Is Nothing Then
On Error GoTo safe_exit
Application.EnableEvents = False
Dim t As Range
For Each t In Intersect(Target, Range("B:B"))
If LCase(t.Value) = "x" Then
'I've made these formulas relative to each target
'you may want to make some absolute references
t.Offset(0, 3) = t.Offset(-1, 2) * t.Offset(-1, 5)
t.Offset(0, 2) = t.Offset(-1, 2)
Else
t.Offset(0, 2).resize(1, 2) = vbnullstring
End If
Next t
End If
safe_exit:
Application.EnableEvents = True
End Sub
Please try below code.
It loop through all non empty rows in column B and check if there is value: x
If so it populate your formulas.
Sub new_sub()
' get last_row of data
last_row = ActiveSheet.UsedRange.Rows.Count
' loop through all rows with data and check if in column B any cell contains value: x
For i = 1 To last_row
' if there is any cell with value: x
' then add below formulas
If Cells(i, 2).Value = "x" Then
' for column E: take value from row above for col D and G and multiple
Range("E" & i).Value = Range("d" & i - 1).Value * Range("G" & i - 1).Value
' for column D: take value from row above
Range("D" & i).Value = Range("D" & i - 1).Value
End If
Next i
End Sub

Paste Special - values only

I am trying to create an audit trail DB, and have the managed to formulate some code to take each line to sheet 2, however I have fallen at the last and cannot work out how to paste values only?
here is my code thus far; any help greatly appreciated
Private Sub Worksheet_Change(ByVal Target As Range)
Dim nxtRow As Integer, b As Boolean
'Determine if change was to Column I (9)
If Target.Column = 9 Then
'If Yes, Determine if cell >= 1
If IsError(Target.Value) Then
b = True
Else
If Target.Value >= 1 Then
b = True
Else
b = False
End If
End If
If b Then
'If Yes, find next empty row in Sheet 2
nxtRow = Sheets(2).Range("A" & Rows.Count).End(xlUp).Row + 1
'Copy changed row and paste into Sheet 2
Target.EntireRow.Copy _
Destination:=Sheets(2).Range("A" & nxtRow)
End If
End If
End Sub
Thanks
Matt
To paste values, you can copy to the clipboard then use the PasteSpecial method, for example:
Target.EntireRow.Copy
Sheets(2).Range("A" & nxtRow).PasteSpecial Paste:=xlPasteValues
This might not solve the problem but it will improve your code.
you open some If-statements but you don't close some which will make your code do something else than you want.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim nxtRow As Integer, b As Boolean
'Determine if change was to Column I (9)
If Target.Column = 9 Then
'If Yes, Determine if cell >= 1
If IsError(Target.Value) Then ' You open this If but you don't close it
b = True
'if you don't close it here the next line (else) will be the else of this if
End If
Else
If Target.Value >= 1 Then
b = True
Else
b = False
End If
'this line had an else if as well. which would just stop your main if statement
If b = True Then
'you say 'if b then' on the line above, which basically does nothing
'If you want to check if b = True for example, do what I did above
'If Yes, find next empty row in Sheet 2
nxtRow = Sheets(2).Range("A" & Rows.Count).End(xlUp).Row + 1
'Copy changed row and paste into Sheet 2
Target.EntireRow.Copy _
Destination:=Sheets(2).Range("A" & nxtRow)
End If
End If
End Sub

Resources