Excel VBA to insert duplicate row below based on drop down menu - vba

I would like to add to the following VBA code, so that when "Did not attend" is selected from dropdown menu a duplicate row is ALSO inserted below the current row within the current worksheet "Details".
Private Sub Worksheet_Change1(ByVal Target As Range)
'Determine if change was made to a single cell in Column E
If Target.Column = 5 And Target.Cells.Count = 1 Then
'Determine if Did not attend was chosen
If Target = "Did not attend" Then
'If Yes...
''Disable Events
Application.EnableEvents = False
''Insert a row below
ActiveCell.Offset(1).EntireRow.Insert
''Copy, Paste
Rows(Target.Row).EntireRow.Copy _
Destination:=Sheets("Non Attendance").Range("A" & nxtRw)
''Re-enable Events
Application.EnableEvents = True
End If
End If
End Sub

This code should do what you want. Please try it.
Private Sub Worksheet_Change(ByVal Target As Range)
' 22 Jan 2018
Dim Rng As Range
Set Rng = Range(Cells(2, "E"), Cells(Rows.Count, "E").End(xlUp))
Debug.Print Target.Address
' Determine if change was made in Column E, below row 1 and above last row
If Not Application.Intersect(Target, Rng) Is Nothing Then
With Target
On Error Resume Next
If .Cells.Count = 1 Then ' if change was in a single cell
'Determine if Did not attend was chosen
If StrComp(.Value, "Did not attend", vbTextCompare) = 0 Then
' If Yes...
Application.EnableEvents = False
.Offset(1).EntireRow.Insert ' Insert a row below
With Worksheets("Non Attendance")
Set Rng = .Cells(.Rows.Count, "A").End(xlUp).Offset(1)
End With
' Copy, Paste
Rows(.Row).EntireRow.Copy Destination:=Rng
Application.EnableEvents = True
End If
End If
End With
End If
End Sub

Related

Applying formula with changing row position to VBA

I have a worksheet that count the number of days between a designated date in column A and today() date in column B which stops the counting in column C if there is the word "CLOSED" in Column D. But I have a problem where I want to reapply back the formula if column D is blank again. I'm not sure how to make the column rows appear at the right place for the formula to be used
Below is the VBA code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells = "CLOSED" Then
'Run only when change is made in Column D
If Target.Column = 4 Then
Application.EnableEvents = False
'Replace the formula with the current result
Range("C" & Target.Row) = Range("C" & Target.Row).Value
Range("B" & Target.Row) = Range("B" & Target.Row).Value
Application.EnableEvents = True
End If
End If
If Target.Cells = "" Then
'Run only when change is made in Column D
If Target.Column = 4 Then
Application.EnableEvents = False
'Replace the formula with the current result
Range("C" & Target.Row).Formula = "=TRUNC($B2 - $A2)"
Range("B" & Target.Row).Value = "=Today()"
Application.EnableEvents = True
End If
End If
End Sub
I would really appreciate it if someone can teach me how to properly change the code:
Range("C" & Target.Row).Formula = "=TRUNC($B2 - $A2)"
as I am still new to VBA programming and would like to learn from my mistake
Below will do what you want. Learn that you can use the .FormulaR1C1 similar to effect of filling up/down. The potential issues including more than 1 cells is changed. Have not put checks if the cells in columns A/B are empty.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim oRng As Range
Application.EnableEvents = False
For Each oRng In Target.Cells
With oRng
If .Column = 4 Then
If UCase(Trim(.Value)) = "CLOSED" Then
.Worksheet.Cells(.Row, "B").Value = .Worksheet.Cells(.Row, "B").Value
.Worksheet.Cells(.Row, "C").Value = .Worksheet.Cells(.Row, "C").Value
ElseIf Len(Trim(.Value)) = 0 Then
.Worksheet.Cells(.Row, "B").Formula = "=Today()"
.Worksheet.Cells(.Row, "C").FormulaR1C1 = "=TRUNC(RC[-2]-RC[-3])"
End If
End If
End With
Next oRng
Application.EnableEvents = True
End Sub
My understanding is that:
you need to act for any column 4 cell change, only
there can be more than one changed cell in column 4
so I'd go like follows (explanations in comments):
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rangeToProcess As Range
Set rangeToProcess = Intersect(Target, Columns(4)) 'mind edited cells in column 4 only
If rangeToProcess Is Nothing Then Exit Sub
Dim cell As Range
Application.EnableEvents = False
For Each cell In rangeToProcess 'loop through edited cells in column 4
With cell.Offset(, -2).Resize(, 2) ' reference a 2-cells range at the left of current cell
Select Case cell.Value 'process current cell value
Case "CLOSED" ' if it's "CLOSED" ...
.Value = .Value ' ... then leave values in referenced cells
Case "" ' if it's "" ...
.FormulaR1C1 = Array("=Today()", "=TRUNC(RC[-1]-RC[-2])") ' ... then restore formulas
End Select
End With
Next
Application.EnableEvents = True
End Sub

Copy cell value to a range of cells

I'm new to VBA and I am trying to copy values from one cell to multiple cells when its value changes.
The value of A2 is constantly changing and when that happens I want that value to be copied to cells C2:C21 (and then eventually to cells D2:D21)
Here is an example of what I would like to achieve:
http://i.stack.imgur.com/xJZyZ.jpg
So far I wrote this code:
Sub Worksheet_Change(ByVal Target As Range)
For i = 0 To 19
If Not Intersect(Target, Range("AS2")) Is Nothing Then
Cells(Target.Row + i, 58).Value = Cells(Target.Row, 45).Value
End If
Next i
End Sub
but this only copies one single value of A2 to all the cells C2 to C22.
May anyone help me write this code properly?
Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("AS2")) Is Nothing Then
For CurCol = 3 to 4
For CurRow = 2 to 21
If Cells(CurRow, CurCol).Value = "" Then
Cells(CurRow, CurCol).Value = Target.Value
Exit Sub
EndIf
Next CurRow
Next CurCol
End If
End Sub
I guess this is what you're after:
Option Explicit
Sub Worksheet_Change(ByVal Target As Range)
Dim nVals As Long
If Not Intersect(Target, Range("A2")) Is Nothing Then
With Range("C2:D21")
nVals = WorksheetFunction.CountA(.Cells)
If nVals = .Count Then Exit Sub
Application.EnableEvents = False
On Error GoTo exitsub
.Cells(nVals Mod .Rows.Count + 1, IIf(nVals >= .Rows.Count, 2, 1)).Value = Target.Value
End With
End If
exitsub:
Application.EnableEvents = True
End Sub

Check values in a range before continuing

So right now I have an excel workbook for a task tracker. When the column that contains the completed date is filled in, it will take that row and copy it onto another sheet ("Complete") then delete it off the current sheet ("Current"). What I would like it to do before this is executed is check the values of columns H through M for either a "C" or "U". If any of the Cells in that range do not contain either or, then I want it to exit out and display a message. I am not to familiar with Excel or VBA, but decent with C++.
Here is the code as of right now:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Dim receivedDate As Range, nextOpen As Range, isect As Range
Set receivedDate = Sheet1.Range("G3:G166")
Set isect = Application.Intersect(Target, receivedDate)
If Not (isect Is Nothing) And IsDate(Target) = True Then
Set nextOpen = Sheet4.Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
Target.EntireRow.Copy Destination:=nextOpen.EntireRow
Target.EntireRow.Delete
End If
Application.EnableEvents = True
End Sub
Here is snip of what I have going on...
snip of work
Any help would be greatly appreciated. Sorry I tried looking around some.
Edit - more robust, added error handler and multi-cell update handling
Private Sub Worksheet_Change(ByVal Target As Range)
Dim receivedDate As Range, nextOpen As Range, isect As Range
Dim rngHM As Range, c As Range, rngDel As Range
Set receivedDate = Sheet1.Range("G3:G166")
'are any of the changed cells in the range we're monitoring?
Set isect = Application.Intersect(Target, receivedDate)
On Error GoTo haveError 'error handler ensures events get re-enabled...
'### remember that Target can contain >1 cell...
For Each c In isect.Cells
If IsDate(c.Value) Then
With c.EntireRow
Set rngHM = .Cells(1, "H").Resize(1, 6)
'EDIT: all cells must be C or U
If (Application.CountIf(rngHM, "C") + _
Application.CountIf(rngHM, "U")) <> rngHM.Cells.Count Then
MsgBox "No C or U on row " & c.Row & " !"
Else
Set nextOpen = Sheet4.Range("A" & Rows.Count) _
.End(xlUp).Offset(1, 0)
.Copy Destination:=nextOpen.EntireRow
'deleting rows while looping gives odd results,
' so store them up until done...
If rngDel Is Nothing Then
Set rngDel = c
Else
Set rngDel = Application.Union(rngDel, c)
End If
End If
End With 'entirerow
End If 'is date
Next c
'delete any copied rows in a single operation
If Not rngDel Is Nothing Then
Application.EnableEvents = False
rngDel.EntireRow.Delete
Application.EnableEvents = True
End If
Exit Sub
haveError:
'if your code errors out then this makes sure event handling gets reset
Application.EnableEvents = True
End Sub

Copy a row of a table when a cell in a specified column changes

I'm trying to copy the row in a table when a cell in a specified column has data inserted then paste this row into another sheet.
The table starts at cell A3 being the first header to the table and it is 9 columns long, there will be an endless amount of rows.
The column to monitor for change is column 8, named "Date Complete". The information entered should always be a date, format "dd mmm".
The row needs to be copied onto a sheet with the same name as the date entered into column 8 which may not exist before the date is entered.
Also before the copying is done I would like a text box to enter notes into the corresponding cell in column 9, named "Notes".
Private Sub Worksheet_change(ByVal Target As Range)
Const lngdatecomplete As Long = 8
Dim wks As Worksheet
Dim lngNextAvailableRow As Long
If Target.Areas.Count = 1 And Target.Cells.Count = 1 Then
If Not Intersect(Target, Columns(lngdatecomplete)) Is Nothing Then
On Error Resume Next
Set wks = ThisWorkbook.Worksheets(Target.Value)
On Error GoTo 0
If wks Is Nothing Then
lngNextAvailableRow = wks.Range("a1").CurrentRegion.Rows.Count + 1
ActiveSheet.Range(Cells(Target.Row, 2), Cells(Target.Row, 8)).copy _
wks.Range("A" & lngNextAvailableRow).PasteSpecial
ElseIf Not wks Is Nothing Then
Dim ShtName$
Sheets.Add after:=Sheets(Sheets.Count)
ShtName = Format(Date, "dd mmm")
Sheets(Sheets.Count).Name = ShtName
Sheets(ShtName).Visible = True
lngNextAvailableRow = wks.Range("a1").CurrentRegion.Rows.Count + 1
ActiveSheet.Range(Cells(Target.Row, 2), Cells(Target.Row, 8)).copy _
wks.Range("A" & lngNextAvailableRow).PasteSpecial
End If
End If
End If
End Sub
The following seems pretty robust and will accept multiple values pasted into column H. I would advise setting a breakpoint on the Application.EnableEvents = False code line and typing a date into column H. Once you arrive at the breakpoint, you can step through each line with the F8 key.
Private Sub Worksheet_change(ByVal Target As Range)
Const lDATECMPLT As Long = 8
If Not Intersect(Target, Columns(lDATECMPLT)) Is Nothing Then
On Error GoTo bm_Safe_Exit
'Application.ScreenUpdating = False
Application.EnableEvents = False
Dim trgt As Range
For Each trgt In Intersect(Target, Columns(lDATECMPLT))
If trgt.Row > 3 And IsDate(trgt) Then
trgt.NumberFormat = "dd mmm"
On Error GoTo bm_Need_WS
With Worksheets(trgt.Text)
On Error GoTo bm_Safe_Exit
trgt.Resize(1, 7).Offset(0, -6).Copy _
Destination:=.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
'optional mark the row copied
'With trgt.Resize(1, 7).Offset(0, -6).Font
' .Strikethrough = True
' .Color = RGB(120, 120, 120)
'End With
End With
End If
Next trgt
End If
GoTo bm_Safe_Exit
bm_Need_WS:
On Error GoTo 0
With Worksheets.Add(after:=Sheets(Sheets.Count))
.Name = trgt.Text
.Visible = True
.Cells(1, 1).Resize(1, 7) = Me.Cells(3, 2).Resize(1, 7).Value2
With ActiveWindow
.SplitColumn = 0
.SplitRow = 1
.FreezePanes = True
.Zoom = 80
End With
End With
Resume
bm_Safe_Exit:
Application.EnableEvents = True
Me.Activate
Application.ScreenUpdating = True
End Sub
I left some extras like copying the headers from the original worksheet into the new worksheet, freezing row 1 on the new worksheet, zooming the new worksheet, etc. Delete or adjust these these if you do not find them helpful.
When you have made all adjustments to the code, uncomment the 'Application.ScreenUpdating = False code line to avoid screen flashes.

Creating a Timestamp VBA

Need Help with this Macro:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 2 Then
Application.EnableEvents = False
Cells(Target.Row, 3).Value = Date + Time
Application.EnableEvents = True
End If
End Sub
Sub DeleteCells()
For Each Cell In Range("B3:B25")
If IsBlank(Cell.Value) Then
Cell.Offset(0, 1).Clear
End If
Next
End Sub
The purpose of this macro is to create a timestamp. First macro works fine. If anything from row B is filled in, a timestamp will be created in row C. However, the delete cells function isn't working. I want it so that if someone deletes a cell in row B, the timestamp will also be deleted.
Try this:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range, c As Range
'anything in ColB?
Set rng = Application.Intersect(Me.Columns(2), Target)
If rng Is Nothing Then Exit Sub 'nothing to process...
Application.EnableEvents = False
'could be >1 cell, so loop over them...
For Each c In rng.Cells
'skip any cells with errors
If c.Row>=3 And Not IsError(c.Value) Then '<<edit
c.EntireRow.Cells(3).Value = _
IIf(Len(c.Value) > 0, Now, "")
End If
Next c
Application.EnableEvents = True
End Sub