Referencing an excel cell that has a variable formula on VBA - excel

I have built an appraisal sheet that allows you select your name from a drop down and all other details about you pop up in other cells. One of such detail will either pop up as Yes or No, depending on whether you manage a team. Now, my VBA code references this cell (F8) that has Yes or No, and it hides or unhides some rows depending on the value of F8. The problem here is that F8 has a formula that was used to derive its value (A Vlookup) and the formula reads
=IFERROR(VLOOKUP($C$6,Data!$E:$I,5,0),"")
My VBA code no longer hides or unhides any cells since I started using a formula in F8. My VBA code is below
ActiveSheet.Activate
If Not Application.Intersect(Range("F8"), Range(Target.Address)) Is Nothing Then
Select Case Target.Value
Case Is = "Yes": Rows("25:26").EntireRow.Hidden = False
Case Is = "No": Rows("25:26").EntireRow.Hidden = True
End Select
End If
End Sub

Range(Target.Address) is actually the same as Target, don't over complicate things.
And ActiveSheet is called ActiveSheet because that sheet is active. So to .Activate an aleady active sheet ActiveSheet.Activate is pretty useless :)
The following should do it.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Application.Intersect(Me.Range("C6"), Target) Is Nothing Then
Select Case Me.Range("F8").Value
Case Is = "Yes": Me.Rows("25:26").EntireRow.Hidden = False
Case Is = "No": Me.Rows("25:26").EntireRow.Hidden = True
End Select
End If
End Sub
But note that if the values in Data!$E:$I that you lookup change then the formula result of F8 =IFERROR(VLOOKUP($C$6,Data!$E:$I,5,0),"") will change without triggering the Worksheet_Change event! So be aware that after changing something in the Data sheet you need to rewrite/re-select the value in C6, to trigger the macro again.

Related

Excel VBA : cells change values depending on specific groups (expanded or collapsed)

I'd like to modify values on specific cells depending on a specific group if it's expanded or collapsed.
I found a way, but it's a manual way (image1 image2) (the macro needs to be launched on each run).
Is there a way to use a function (i.e. worksheet_change), so that will be on real time ?
P.S. Sorry for my bad English and be kind, I'm kinda new on VBA (first code).
Thank you.
Private Sub groups()
If Worksheets("Feuil1").Columns("F").ShowDetail = True Then
Range("K2:K7").Value = "YES"
Else
Range("K2:K7").Value = "NO"
End If
End Sub
Thank you Luuklag for your solution, but as I said in my comment, in your code I have to update manually the placeholder cell which is not what I'm looking for.
But, I found something where my cells get updated by expanding or collapsing my group. And for this, as you said, I need a placeholder cell that gets updated on each calculation.
I use the formula =NOW on cell A1, because it's always useful to know the time and date.
Here is the (combined) code, for those who are looking a solution :
Private Sub Worksheet_Calculate()
Application.EnableEvents = False
'Where F is the column having the group button
If Columns("F").ShowDetail = True Then
'This is where you choose the cells that are dependent to the group and attribute something
Range("G10:G19").Value = "YES"
Else
'Same here. It could be other cells too
Range("G10:G19").Value = "NO"
End If
Application.EnableEvents = True
End Sub
There is a simple solution to this. Every time you expand or collapse a group you trigger the worksheet_calculate event. This can be used to your advantage.
All you need is a placeholder cell, which you populate with a volatile function (a function that changes its value on each calculation). You can use =randbetween(1,10) or =NOW() for example.
You then have your worksheet change event to look for your placeholder cell, AA1 in this example.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("AA1")) Is Nothing Then
Call groups
End If
End Sub

VBA - How to lock entire column based on a cell value in this column

I'm sorry this question may look like antoher ones, but I am new in VBA and struggle to get a proper code...
I would like to protect some data after they were verified. For exemple, I have data in Column B (or whatever column) and I check them in comparaison to manuscrit raw data. I would like to have a cell in that column where I say "Yes" to testify this was checked. After entering "Yes", I would like that all cells in the colum become locked.
I've found a code to lock an entire row (Lock rows in Excel using VBA), but whatever i try, i'm not able to modifiy it to work for a variable entire column (only to lock specific column, I'm not able to lock the column where "Yes" is typed ...)
Could someone help me ?
Thanks !
Maybe this solution can help:
Step 1: select all cells in a sheet. Goto properties (cell format) -> security and deaktivate the checkbox for lock cells (see picture below).
Step 2: protect the sheet with a password. In my example I used "billytalent".
Step 3: copy the following code into the code-area of the sheet. Therefore open the Visual Basic Editor. On the left side you will find a list with your sheets. Double click on the sheet where you want to lock cells with entry "yes". Copy the procedure into the code-area.
Private Const PASSW As String = "billytalent"
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cell As Range
For Each cell In Target
'only do something, if input is in row 2
If cell.Row = 2 Then
'only do something, if someone write yes in a cell
If cell.Value = "yes" Then
'deaktivate the protection of the sheet
ActiveSheet.Unprotect Password:=PASSW
'lock the cells in the column
ActiveSheet.Columns(cell.Column).Locked = True
'activate the protection
ActiveSheet.Protect Password:=PASSW, userinterfaceonly:=True, AllowFiltering:=True, AllowFormattingCells:=True, AllowFormattingRows:=True, AllowFormattingColumns:=True
ActiveSheet.EnableOutlining = True
End If
End If
Next
End Sub
You can tweak the code you're looking at there a little and I think it will do what you want. Make sure before you start this that you set all the cells on the sheet to unprotected.
This is set to check row 3 of the sheet for Yes. Change the value on the second line if you need to.
Private Sub Worksheet_Change(ByVal Target As Range)
row_to_check = 3 ' Checking row 3 for "Yes"
If Intersect(Target, Me.Rows(row_to_check)) Is Nothing Then Exit Sub ' exit early if row 3 wasn't changed
Me.Unprotect ' unprotect the sheet
For Each r In Target.EntireColumn.Columns ' cycle through each row that has seen a change
r.Locked = r.Cells(row_to_check, 1).Value = "Yes" ' set it to protected if the second cell on that row is "Yes"
Next
Me.Protect ' reprotect the sheet
End Sub

Hide and unhide rows based on a value

I am trying to create a survey in Excel and want to hide and unhide rows based on their answers. For example, if D3 = "no" hide rows D4:D10, and I want to repeat this multiple times throughout, but the number of rows to hide changes. So if D3 = "yes" leave unhidden. Then move to answer D5, if D5 = "no" hide rows D6:D7. And this continues on and on throughout.
Using the worksheet_change() event. In your VBE double click the worksheet where this change (this cell) will happen. Then enter:
Private Sub Worksheet_Change(ByVal Target As Range)
'Detect if the worksheet change was on cell D3
If Not (Intersect(Target, Range("D3")) Is Nothing) Then
'Hide rows if the value of D3 is "No"
Range("D4:D10").EntireRow.Hidden = (Range("D3").Value = "No")
End If
End Sub
Every time a change happens on this worksheet this subroutine will fire off, test if the change occured in cell "D2" then toggle the row's hidden property based on the value.
The Hidden property of the EntireRow range object takes a True or False value, so we are able to just set it equal to the result of the conditional statement (Range("D3").value = "No") which will return a True or False greatly simplifying the amount of code you need to write.
You'll just need to add more If Not (Intersect(Target, Range("whatever")) Is Nothing) Then lines to test for your other cells like D5 and hide the appropriate rows base on whatever value you are testing for in that cell.
If that gets to be too much code (testing all those intersects) you can just test the intersects once like:
If Not (Intersect(Target, Union(Range("D3"), Range("D5"), Range("D8"))) Is Nothing) Then
'And then in here your individual lines that toggle the hidden property:
Range("D4:D10").EntireRow.Hidden = (Range("D3").Value = "No")
Range("D6:D7").EntireRow.Hidden = (Range("D5").Value = "No")
...
End If
Lastly, because this beast will fire any time any change is made on this worksheet, you may want to shut off event firing while the subroutine is running. So turn enableEvents off at the top of the subroutine and turn it back on at the end:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If Not (Intersect(Target, Union(Range("D3"), Range("D5"), Range("D8"))) Is Nothing) Then
Range("D4:D10").EntireRow.Hidden = (Range("D3").Value = "No")
Range("D6:D7").EntireRow.Hidden = (Range("D5").Value = "No")
Range("D9:D12").EntireRow.Hidden = (Range("D8").Value = "No")
End If
Application.EnableEvents = True
End Sub
This will prevent this same subroutine getting called by itself while it's busy changing the sheet causing an infinite loop and locking up excel (which sucks if you didn't save the workbook before firing it off).

Excel clear contents of drop down based on another cell being cleared

I have a cell on Sheet1 that contains a drop-down list, let's say N3. The items in the drop down change, depending on the value in J3. At start, both cells are blank. Enter data in J3, and the drop down populates in N3. If I clear the contents of J3, the drop down in N3 is now empty, but the last selected value (if one was selected), still appears as a 'ghost' entry. It's a ghost entry to ME because it is old data, but I do understand the software is doing as designed. If J3 is cleared of contents, how do I get N3 to be cleared of that last selection? I am not VBA trained, but dangerous enough to handle it if that's what's needed to accomplish this. thanks!
You may consider to use the worksheet_change event.Put the below code in sheet1 code module.
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo err_rout
Application.EnableEvents = False
If Not Intersect(Range("J3"), Target) Is Nothing And Target.Value = vbNullString Then
Range("N3").Value = vbNullString
End If
err_rout:
Application.EnableEvents = True
End Sub

Why doesn't locking a cell in a protected worksheet in Excel prevent selection?

I'm working on a protected Excel spreadsheet and ran into a problem with cells that I've programmatically locked that are still selectable. I can't click on them directly to select them, but if I select the cell to the lower right of a locked cell and then shift-click the one to the upper left, all 9 cells (including the 'locked' one) are selected. I can also click-drag to select the 9 cells. I'm using the following VBA code to protect and set the selection criteria:
Worksheets("Sheet1").Protect UserInterfaceOnly:=True
Worksheets("Sheet1").EnableSelection = xlUnlockedCells
I've tried the two commands in the reverse order and get the same results.
I've also used the Excel cell formatting / protection menus to do the same thing and get the same results.
Am I missing something obvious or is there some other programmatic way to mark a cell so that it can't be selected later on?
I think you'll need to create some code in the Worksheet_SelectionChange event that checks whether your protected cells are included in the new selection and, if so, selects some other cell (perhaps the next unprotected one to the right or below).
I haven't reviewed the code, but a cursory search for "Worksheet_SelectionChange protected cells selection" brought up http://www.vbaexpress.com/kb/getarticle.php?kb_id=383.
You not missing anything, this is simply Excel maintaining the shape of the selection in preference to the protection status of the cells.
The cells are still protected, but can be copied.
Using the Worksheet_SelectionChange event will allow you to run code to redirect the selection of protected cells to another cell. This code needs to be stored in the sheet you are trying to protect.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim Selectedrange As Range
Dim ProtectedRange As Range
Dim ws As Worksheet
Application.EnableEvents = False
Set ProtectedRange = ActiveSheet.Range("A1:A10")
Set Selectedrange = Intersect(Target, ProtectedRange)
If Selectedrange Is Nothing Then
Exit Sub
Else
ActiveSheet.Range("B1").Select
End If
Application.EnableEvents = True
End Sub
If you just want to stop the user copying out the formulas then just add a line to your code to set 'Formula Hidden' to true. If the protected cells are copied, only the values will be copied.
Worksheets("Sheet1").Range("A1:A10").Locked = True
Worksheets("Sheet1").Range("A1:A10").FormulaHidden = True
Worksheets("Sheet1").Protect UserInterfaceOnly:=True, Password:="123"
Worksheets("Sheet1").EnableSelection = xlUnlockedCells
An alternate is to move your protected data into another sheet and set it visibilty to 'very hidden', so that it is no longer visible through the UI. The values in the 'very hidden' sheet can still be accessed via formula.
Worksheets("Sheet2").Visible = xlVeryHidden

Resources