Automatically copy row to another workbook/worksheet when specific cell in the row is updated - vba

I've searched online and couldn't find a code to do what I'm looking to do and I hit a tumbling block..
We're currently looking to implement a CRM-like reporting system for our reps in excel. Our reps would fill out customer data in a row and just update the relevant cells when the account status changes one way or another.
The report is all built and works but we're lacking the account history part so what we're looking to do, is to copy the whole row in a new row to a different sheet or workbook any time the data in column I is updated for a row so there's a history of all relevant changes kept automatically on a separate sheet or worksheet.
I've searched and looked online at different codes and the tracking changes option but could not find a code that would automatically copy only the whole relevant row on update and we really need the whole row to be copied for the data to remain meaningful to us so track changes doesn't work for our needs. We'd also require for these steps to happen without action from our users.
Any help on how this could be accomplished would be greatly appreciated.

Use the WorksheetChangeEvent to detect when something has been changed:
Private Sub Worksheet_Change(ByVal Target As Range)
' do stuff
End Sub
Put the above code into the worksheet object (double click on the worksheet in the code editor).
Use Application.Intersect to narrow down what has been changed. For instance if you're only interested in cells I1 to I10000:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Application.Intersect(Target, Range("I1:I1000")) Is Nothing Then
' do stuff
End If
End Sub
Then copy the required row:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Application.Intersect(Target, Range("I1:I10000")) Is Nothing Then
Rows(Target.Row).copy
' paste it where you want it
End If
End Sub
Target is the range for the affected cell. Of course the user can affect more than one cell at once e.g. by autofilling, so you may need to put some additional logic e.g if Target.Rows.Count > 1, but you get the idea.

Related

Apply autofilter using macro after worksheet has calculated?

So I've set up this spreadsheet at work - I end up having to do a lot of fiddly Excel tasks, though I barely know any VBA - and I want a table to automatically filter itself after the worksheet has been edited. The problem is that the column which is being filtered is full of formulas, which change in response to edits made by the user, and the filter gets applied before the column has finished calculating, producing erratic results. So really what I want is to apply AutoFilter after the worksheet has been calculated, rather than after it has been edited.
The macro I have been using is:
Private Sub Worksheet_Change(ByVal Target As Range)
With ActiveWorkbook.Worksheets("Library").ListObjects("Library")
.AutoFilter.ApplyFilter
End With
End Sub
Naively changing the activating event to Worksheet_Calculate() doesn't work - it appears to be repeatedly applying the filter over and over again.
I'm sure this is a relatively simple one and I just don't know what it is I need to do. Can you guys advise?
(PS first time posting here - hope I have done everything right!)
Never mind, have solved it myself. For anyone else with the problem, I just set calculation to manual and then replaced my code with:
Private Sub Worksheet_Change(ByVal Target As Range)
Calculate
ActiveWorkbook.Worksheets("Library").ListObjects("Library").AutoFilter.ApplyFilter
End Sub

copy row to next free row on another spreadsheet on change

First off, I'm a noob when it comes to Macros and VBA, so please forgive me if I don't make sense.
I've got an Excel spreadsheet which is basically a list of users and their mobile phone numbers and some other bits (columns A-K are currently used) and it's ordered by rows.
What I need is a way of copying the whole row if I change a cell. So if I change the username, it copies the whole row of that user to the next blank row on a second sheet.
The purpose of this is to keep an audit trail allowing us to see who's previously used a number etc.
I found this: Copy row to another sheet in excel using VBA which is working as intended, but I can't for the life of me get it to a, copy the cells to the next free row, or b, not overwrite the existing entry.
This is the code I'm using:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim a As Range, rw As Range
For Each a In Selection.Areas
For Each rw In a.Rows
If rw.Row >= 2 Then
rw.EntireRow.Copy Sheet2.Cells(2 + (rw.Row - 2) * 3, 1)
End If
Next rw
Next a
End Sub
I'd really appreciate it if someone could help me customise it.
I'm using Excel 2010 on Win7.
Many thank in advance.
Typically the Intersect method is used to determine if the cell or cells receiving a change involve one or more columns that you are concerned with. You can add additional parameters; in this case, I've .Offset the Worksheet.UsedRange property down one row to make sure that row 1 is not involved.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Columns(1), Me.UsedRange.Offset(1, 0)) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False 'not really necessary in this case but never a bad idea within a Worksheet_Change
Dim a As Range
For Each a In Intersect(Target, Columns(1), Me.UsedRange.Offset(1, 0))
If CBool(Len(a.Value2)) Then _
a.EntireRow.Copy _
Destination:=Sheet2.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0) 'not really sure this is the correct destination
Next a
End If
bm_Safe_Exit:
Application.EnableEvents = True
End Sub
I've included a call to disable event handling for the duration of the Worksheet_Change event macro. While this is a critical step when the Worksheet_Change modifies values, it is not really important to incorporate here. However, it does not harm and is already in place in case you want to augment the Worksheet_Change to include something like a timestamp that would change the values on the worksheet.

Saving values upon excel cell deletion

So, I'm back with a more specific answer/problem.
Also, I'm sorry, I picked up excel (hadn't actually used the program) a few weeks back only and minimal usage. So if the code is bad/explanations unclear, comment and i'll do my best to get this together.
I am currently in a situation with two separate (albeit linked) excel files.
Src (Book1)
Dest (Book2)
They each have one worksheet.
The idea is that Src will be modified (including deletion and insertion of rows) and i need these changes to be reflected onto Dest.
I have the insertion so far, scrounged up a little bit of code using Before_DoubleClick.
However i am having a few issues on deletion.
What i have this far is :
Private Sub Worksheet_Change(ByVal Target As Range)
Const destBook As String = "Book2"
Const destSheet As String = "Sheet2"
Dim wb1 As Workbook
Set wb1 = Workbooks(destBook)
' Here is the main problem i have. I need a better way to detect
' deletion of one or more rows. Otherwise the Application.Undo
' re-enters the if and it just loops.
If Target.Address = Target.EntireRow.Address Then
' Here i Undo the deletion to be able to copy the values.
Application.Undo
Target.Copy
' I also haven't found a way to delete again but google can help me on that
' Pasting line
'wb1.Sheets(destSheet).Cells(Target.Row, 1).PasteSpecial Paste:=xlPastValues
End If
End Sub
Ideally, what should happen is, upon deletion of one or more rows, i would like to undo the last action, copy the data, delete the row and finally past the data in another worksheet. However, as of now i am blocked at undoing the last action. It calls my VBA macro again and just starts looping.
Im not sure what you want but you either have to replace formulas with values in the new cells, or if those cells are supposed to have a formula you probably have to do
application.Calculation=xlCalculationManual
make the deletion or change then
application.Calculation=xlCalculationAutomatic
to turn autocalculation back on
Manual is tricky because if code crashed you would want to make sure you didn't leave the sheet in a state that didn't calculate

Change a date in EXCEL based on changes to other cells

I am trying to automate the updating of a status date in an Excel Worksheet based on if any changes have taken place within certain cells. In my example, I want the date in cell "S6" to equal today's date is any of the data in cells "B6:L34" have been changed/ deleted/ info added. I am not sure what VBA code to use or how. Any clues? This would be for only changes within those cells on that worksheet; not changes throughout the Workbook. Thank you.
I would look into workbook/worksheet events throughout the internet. You can create private sub functions that automatically runs whenever a change is made. It sounds like you need a private sub worksheet_selection or worksheet_change event handler. Look up something simple like "workbook_open VBA excel" and you can get A great feeler for how event handlers work.
Then I suggest you to research the INTERSECT function and play around with it. It allows you to declare a TARGET variable and range for you to manipulate, basically saying that if anything happens to that range, this is how I want to manipulate the TARGET. The TARGET is basically the cell that was being manipulated within the range.
There might be other factors - but this will start you off very quickly
This code will update the cell S6 with today's date when anything inside the range B6:L34 has been edited.
Private Sub Worksheet_Change(ByVal Target As range)
If Not Intersect(Target, Target.Worksheet.range("B6:L34")) Is Nothing Then
Sheets("Sheet1").Range("S6") = Date
End If
End Sub
EDIT:
For this to work, make sure this code is placed within the sheet that you're using (see below):

Call a function when only a specific Excel cell changes on Formula Recalculation

As far as i know, Worksheet_Calculate is called when the value of any cell in a worksheet changes on Formula recalculation.
Is there a way so that i need a function to be called only when a specific cell changes on Formula Recalculation
To make something happen when a specific cell is changed, you need to embed the relevant selection change event within the file Worksheet_Change(byval target as Range). We can re-calculate a worksheet when your cell changes as follows:
Private Sub Worksheet_Change(byval target as range)
If target.address = Range("YourCell").Address Then Application.Calculate
End Sub
Now what you want to do is switch off calculations the rest of the time. If you only want to switch off calculations on the single sheet (and not your whole file), you will need to turn calculations off when it is activated, and on when deactivated e.g.
Private Sub Worksheet_Activate
Application.Calculation = xlCalculationManual
End Sub
Private Sub Worksheet_Deactivate
Application.Calculation = xlCalculationAutomatic
End Sub
Of course, your requirements to re-calculate may be considerably more complex than the example above. Firstly, you may open the file whilst on the sheet in question in which case you should use the Workbook_Open event to detect your sheet, and set calculations accordingly
Then you may have several cells that may require some sort of calculation. Presumably the reason you want to switch off calculations is that the file is running too slowly. If so, and you are identifying all the input cells, you could enter the outputs using code. One method would be to enter the formulas using this guide to entering formulas in Excel Visual Basic. You could then replace the formula with the calculated value e.g. Range("YourCell") = Range("YourCell").Value...so stopping the number of formulas in the sheet constantly growing
Let me see if I interpret your question correctly. You want to know if it is possible to only kickoff a macro if a particular cell (or group of cells) is changed.
The answer is Yes. To tweak Ed's code a little.
Private Sub Worksheet_Change(byval target as range)
If Not Intersect(target.address, Range("YourCells")) is Nothing Then
MyMacro()
End If
End Sub
I think your use of "function" is throwing people off. That's why Ed's answer is so elaborate.
Ok. It is possible that you stated your question correctly and you just want to gain efficiency. In that case, Ed's answer solves your immediate problem, but will cause the spreadsheet NOT to calculate automatically when you change other cells.