Combining IF else with LEFT to hide columns - excel

I'm trying to write some code to Hide columns if the first 3 characters of cells in a range equal the contents of another. I have the code for hiding columns if cells in a range are blank as this;-
Private Sub Worksheet_Change(ByVal Target As Range)
Dim r As Range, cell As Range
On Error GoTo ErrHandler
Set r = Me.Range("C8:R8")
Application.ScreenUpdating = False
Application.EnableEvents = False
For Each cell In r
If cell.Value = "" Then
cell.EntireColumn.Hidden = True
Else
cell.EntireColumn.Hidden = False
End If
Next
ErrHandler:
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
And the code for identifiying the first 3 charcters of a cell;-
Dim LResult As String
LResult = Left ("Alphabet",3)
But how do I combine the two, referencing a specific cell rather than "Alphabet"?
Cant get this to work - any suggestions?
Private Sub Worksheet_Change(ByVal Target As Range)
Dim r As Range, cell As Range
On Error GoTo ErrHandler
Set r = Me.Range("B7:CG7")
Application.ScreenUpdating = False
Application.EnableEvents = False
Row = 1
col = 1
For Each cell In r
If cell.Value = "" And Left(cell.Value, 3) = cell(Row, col).Value Then
cell.EntireColumn.Hidden = True
Else
cell.EntireColumn.Hidden = False
End If
Next
ErrHandler:
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
Cheers

You have almost the working code. You are comparing cell.Value to an empty string - now just apply Left to it
LResult = Left (cell.Value,3)
Edit:
row = 20
col = 30
For Each cell In r
If cell.Value = "" and Left (cell.Value,3) = Cell(row, col).Value Then
cell.EntireColumn.Hidden = True
Else
cell.EntireColumn.Hidden = False
End If
where you want data from cell at row and col (I used 20, 30 as the example)

Related

Link 2 Data Validation Cells

I am trying to link 2 cells that have data validation lists in them so that when 1 of the cells (ex. cell A2) is filled with the SKU in from a selection in the dropdown list, cell B2 will be filled with the SKU description and vice versa.
See the pictures below with that I have so far. I have named the columns:
Column A = a_val
Column B = b_val
SKU column with values = vrac
SKU description column with values = vrac_description
Table with SKUs and SKU descriptions = description
See the attached pictures for what I currently have.
1 sheet is the empty fields, I have data validation lists on columns A and B since I want to be able to have the option to select either from column A or column B but would like either one to auto-populate when I've selected an item from the list in the opposite cell
Thank you!
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("a_val")) Is Nothing Then
With Application.WorksheetFunction
UI False
Range("b_val").Value = .Index(Range("vrac_description").Value, .Match(Range("a_val").Value, Range("description").Value, 0))
UI True
End With
ElseIf Not Intersect(Target, [b_val]) Is Nothing Then
With Application.WorksheetFunction
UI False
[a_val].Value = .Index([vrac], .Match([b_val], [vrac_description], 0))
UI True
End With
End If
End Sub
Public Sub UI(t As Boolean)
Application.EnableEvents = t
Application.ScreenUpdating = t
End Sub
Current Code
Main Sheet
Data Validation Lookup
[EDIT} New code attempt:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, a_val) Is Nothing Then
With Application.WorksheetFunction
UI False
'b_val = .VLookup(Target, Description, 1, 0)
Range(Target.Column + 1).Value = .Index(vrac_description, .Match(Target.Value, vrac, 0))
UI True
End With
ElseIf Not Intersect(Target, b_val) Is Nothing Then
With Application.WorksheetFunction
UI False
'Range(Target.Column - 1).Value = .VLookup(Target.Value, Description, 1, 0)
Range(Target.Column - 1).Value = .Index(vrac, .Match(Target.Value, vrac_description, 0))
UI True
End With
End If
End Sub
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Msgbox "Target=" & Target.Address
On Error GoTo errorexit
Dim r, i As Long, cell As Range
i = Target.Column
If i > 2 Or Target.Value = "" Then Exit Sub
Set cell = Target.Offset(, 3 - i * 2)
With Sheets("Data_Validation").ListObjects("description").DataBodyRange
r = Application.Match(Target.Value, .Columns(i), 0)
If Not IsError(r) Then
Application.EnableEvents = False
cell = .Cells(r, 3 - i).Value
Else
MsgBox Target.Value & " not found in column " & i
End If
End With
errorexit:
Application.EnableEvents = True
End Sub
Your code corrected
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo exiterror
Dim a_val As Range, b_val As Range
Dim vrac As Range, vrac_description As Range
' define ranges
With ThisWorkbook
Set a_val = .Names("a_val").RefersToRange
Set b_val = .Names("b_val").RefersToRange
Set vrac = .Names("vrac").RefersToRange
Set vrac_description = .Names("vrac_description").RefersToRange
End With
If Not Intersect(Target, a_val) Is Nothing Then
With Application.WorksheetFunction
UI False
Target.Offset(, 1).Value = .Index(vrac_description, .Match(Target.Value, vrac, 0))
UI True
End With
ElseIf Not Intersect(Target, b_val) Is Nothing Then
With Application.WorksheetFunction
UI False
Target.Offset(, -1).Value = .Index(vrac, .Match(Target.Value, vrac_description, 0))
UI True
End With
End If
exiterror:
Application.EnableEvents = True
End Sub

Dynamically Hide/Unhide Multiple Ranges Using VBA With Minimal Lag

I am trying to dynamically hide or unhide rows in a worksheet based off of selections within dropdown menus.
The script that I have works with smaller data sets, but because I have 35 different ranges of 26 rows each this slows down really quickly.
I have seen several solutions offered to similar question here, but I have been unable to get them to work.
I want to collect the value in cells B15 down to B41 and hide any rows that have a blank value, then repeat for the remaining 34 ranges.
Each of the cells in the range above have a formula that can return a "" value (which are the rows I want to hide).
Private Sub Worksheet_Change(ByVal Target As Range)
'Turns off worksheet protection to allow for hiding and unhiding of rows
ActiveSheet.Unprotect "xxxx"
'Turns off screen updating and animations while hiding and unhiding rows
Application.EnableAnimations = False
Application.ScreenUpdating = False
Hide1
Hide2
Hide3
Hide4
Hide5
Hide6
Hide7
Hide8
Hide9
Hide10
Hide11
Hide12
Hide13
Hide14
Hide15
Application.ScreenUpdating = True
Application.EnableAnimations = True
ActiveSheet.Protect "xxxx"
End Sub
Sub Hide1()
Application.EnableEvents = False
Application.EnableAnimations = False
Application.ScreenUpdating = False
'Run #1
If Range("B15").Value = "" Then
Rows(15).EntireRow.Hidden = True
Else
Rows(15).EntireRow.Hidden = False
End If
If Range("B16").Value = "" Then
Rows(16).EntireRow.Hidden = True
Else
Rows(16).EntireRow.Hidden = False
End If
If Range("B17").Value = "" Then
Rows(17).EntireRow.Hidden = True
Else
Rows(17).EntireRow.Hidden = False
End If
If Range("B18").Value = "" Then
Rows(18).EntireRow.Hidden = True
Else
Rows(18).EntireRow.Hidden = False
End If
If Range("B19").Value = "" Then
Rows(19).EntireRow.Hidden = True
Else
Rows(19).EntireRow.Hidden = False
End If
If Range("B20").Value = "" Then
Rows(20).EntireRow.Hidden = True
Else
Rows(20).EntireRow.Hidden = False
End If
If Range("B21").Value = "" Then
Rows(21).EntireRow.Hidden = True
Else
Rows(21).EntireRow.Hidden = False
End If
If Range("B22").Value = "" Then
Rows(22).EntireRow.Hidden = True
Else
Rows(22).EntireRow.Hidden = False
End If
If Range("B23").Value = "" Then
Rows(23).EntireRow.Hidden = True
Else
Rows(23).EntireRow.Hidden = False
End If
If Range("B24").Value = "" Then
Rows(24).EntireRow.Hidden = True
Else
Rows(24).EntireRow.Hidden = False
End If
If Range("B25").Value = "" Then
Rows(25).EntireRow.Hidden = True
Else
Rows(25).EntireRow.Hidden = False
End If
If Range("B26").Value = "" Then
Rows(26).EntireRow.Hidden = True
Else
Rows(26).EntireRow.Hidden = False
End If
If Range("B27").Value = "" Then
Rows(27).EntireRow.Hidden = True
Else
Rows(27).EntireRow.Hidden = False
End If
If Range("B28").Value = "" Then
Rows(28).EntireRow.Hidden = True
Else
Rows(28).EntireRow.Hidden = False
End If
If Range("B29").Value = "" Then
Rows(29).EntireRow.Hidden = True
Else
Rows(29).EntireRow.Hidden = False
End If
If Range("B30").Value = "" Then
Rows(30).EntireRow.Hidden = True
Else
Rows(30).EntireRow.Hidden = False
End If
If Range("B31").Value = "" Then
Rows(31).EntireRow.Hidden = True
Else
Rows(31).EntireRow.Hidden = False
End If
Application.EnableEvents = True
Application.EnableAnimations = True
Application.ScreenUpdating = True
End Sub
Please, try the next code. As it is set, it will hide all rows having empty values returned by a formula. firstRand lastR can be chosen to process a specific number of rows:
Sub Hide1()
Dim sh As Worksheet, lastR As Long, firstR As Long
Dim rng As Range, rngH As Range, arr, i As Long
Set sh = ActiveSheet 'use here the sheet you need
lastR = sh.Range("B" & sh.rows.Count).End(xlUp).row 'last row on B:B
firstR = 15 'first row of the range to be processed
Set rng = sh.Range("B" & firstR & ":B" & lastR)
rng.EntireRow.Hidden = False 'show all rows in the range
arr = rng.Value 'place the range in an array for faster iteration
For i = 1 To UBound(arr)
If arr(i, 1) = "" Then
If rngH Is Nothing Then 'set the range to keep the cells where the rows must be hidden
Set rngH = rng.cells(i, 1)
Else
Set rngH = Union(rngH, rng.cells(i, 1))
End If
End If
Next
'hide the rows at once:
If Not rngH Is Nothing Then rngH.EntireRow.Hidden = True
End Sub
Hide Blank Rows
Adjust the values in the constants section.
Option Explicit
Sub HideBlankRows()
Const fCellAddress As String = "B16"
Const crgCount As Long = 35
Const crgSize As Long = 16 ' maybe 26 ?
Const crgGap As Long = 5
Dim ws As Worksheet: Set ws = ActiveSheet
Dim crg As Range: Set crg = ws.Range(fCellAddress).Resize(crgSize)
Dim crgOffset As Long: crgOffset = crgSize + crgGap
Dim rg As Range: Set rg = crg
Dim n As Long
For n = 2 To crgCount
Set crg = crg.Offset(crgOffset)
Set rg = Union(rg, crg)
Next n
Dim drg As Range
Dim cCell As Range
For Each cCell In rg.Cells
If Len(CStr(cCell.Value)) = 0 Then
If drg Is Nothing Then
Set drg = cCell
Else
Set drg = Union(drg, cCell)
End If
End If
Next cCell
If drg Is Nothing Then Exit Sub
rg.EntireRow.Hidden = False
drg.EntireRow.Hidden = True
End Sub

Update excel cell with date if a cell in a range is update

I need to update a cell with the date and time stamp (NOW()) if any cell is updated within any cell before it within that same row.
So update cell "CU" with date and time when any cell from "A-CR" is updated.
I have done some searching but I can only seem to find bits that work if only updating a single cell, I'm looking for if anything changes within that range.
I currently have some Vba which does something similar which will update the adjacent cell with time and date which is required but I also need an overall one for the whole process.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("F:F, I:I, L:L, O:O, R:R, U:U, X:X, AA:AA, AB:AB, AE:AE, AH:AH, AK:AK, AN:AN, AQ:AQ, AT:AT, AW:AW, AZ:AZ, BC:BC, BF:BF, BI:BI, BL:BL, BO:BO, BR:BR, BU:BU, BX:BX, CA:CA, CD:CD, CG:CG, CJ:CJ, CM:CM, CP:CP")) Is Nothing Then
On Error GoTo safe_exit
With Application
.EnableEvents = False
.ScreenUpdating = False
Dim trgt As Range, ws1 As Worksheet
'Set ws1 = ThisWorkbook.Worksheets("Info")
For Each trgt In Intersect(Target, Range("F:F, I:I, L:L, O:O, R:R, U:U, X:X, AA:AA, AB:AB, AE:AE, AH:AH, AK:AK, AN:AN, AQ:AQ, AT:AT, AW:AW, AZ:AZ, BC:BC, BF:BF, BI:BI, BL:BL, BO:BO, BR:BR, BU:BU, BX:BX, CA:CA, CD:CD, CG:CG, CJ:CJ, CM:CM, CP:CP"))
If trgt <> vbNullString Then
If UCase(trgt.Value) = "Y" Or UCase(trgt.Value) = "N" Then
Cells(trgt.Row, trgt.Column + 1) = Now()
Cells(trgt.Row, trgt.Column + 2) = Environ("username")
'Select Case trgt.Column
' Case 2 'column B
' Cells(trgt.Row, trgt.Column + 1) = Environ("username")
' Case 4 'column D
' 'do something else
' End Select
Else
trgt = ""
Cells(trgt.Row, trgt.Column + 1) = ""
Cells(trgt.Row, trgt.Column + 2) = ""
End If
End If
Next trgt
'Set ws1 = Nothing
End With
End If
safe_exit:
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
This works for me:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If Intersect(Target, Me.Range("A" & Target.Row & ":CR" & Target.Row)) Is Nothing Then GoTo SafeExit
Me.Cells(Target.Row, "CU") = Now()
SafeExit:
Application.EnableEvents = True
End Sub
The below code takes care of:
Clearing the time if the row is blank.
Updating the time only if the values really change from the previous value.
Dim oldValue As String
'Change the range below where your data will be
Const RangeString = "A:CR"
'Below variable decides the column in which date will be displayed
'Change the below value to 1 for column A, 2 for B, ... 99 for CU
Const ColumnIndex = 99
Private Sub Worksheet_Change(ByVal Target As Range)
Dim WorkRng As Range
Dim HorizontalRng As Range
Dim Rng As Range
Dim HorRng As Range
Dim RowHasVal As Boolean
Set WorkRng = Intersect(ActiveSheet.Range(RangeString), Target)
If Not WorkRng Is Nothing Then
If WorkRng.Cells.Count = 1 And WorkRng.Cells(1, 1).Value = oldValue Then
Exit Sub
End If
Application.EnableEvents = False
For Each Rng In WorkRng
Set HorizontalRng = Intersect(ActiveSheet.Range(RangeString), Rows(Rng.Row))
RowHasVal = False
For Each HorRng In HorizontalRng
If Not VBA.IsEmpty(HorRng.Value) Then
RowHasVal = True
Exit For
End If
Next
If Not RowHasVal Then
ActiveSheet.Cells(Rng.Row, ColumnIndex).ClearContents
ElseIf Not VBA.IsEmpty(Rng.Value) Then
ActiveSheet.Cells(Rng.Row, ColumnIndex).Value = Now
ActiveSheet.Cells(Rng.Row, ColumnIndex).NumberFormat = "dd-mm-yyyy, hh:mm:ss"
End If
Next
Application.EnableEvents = True
End If
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not Intersect(Target, ActiveSheet.Range(RangeString)) Is Nothing Then
If Target.Cells.Count = 1 Then
oldValue = Target.Value
Else
oldValue = ""
End If
End If
End Sub

Combining Not Intersect, Target.Parent.Range and Worksheets.Cells

I am aiming to add VBA that hides or shows rows depending on whether a user clicks on a specific cell that needs to loop many times.
I was wondering how to possibly combine Target.Parent.Range with Worksheet.Cells so that I can write a loop for it rather than repeating the code multiple times. The below code works fine but seems pretty inefficient:
'Hide1
If (ActiveSheet.Name = "Dashboard") And Not Intersect(Target, Target.Parent.Range("G38")) Is Nothing Then
If Rows("40:47").EntireRow.Hidden = True Then
Rows("40:47").EntireRow.Hidden = False
Range("G38").Value = "Hide"
ActiveSheet.Range("A1").Select
Else
Rows("40:47").EntireRow.Hidden = True
Range("G38").Value = "Show"
ActiveSheet.Range("A1").Select
End If
End If
'Hide2
If (ActiveSheet.Name = "Dashboard") And Not Intersect(Target, Target.Parent.Range("G48")) Is Nothing Then
If Rows("50:57").EntireRow.Hidden = True Then
Rows("50:57").EntireRow.Hidden = False
Range("G48").Value = "Hide"
ActiveSheet.Range("A1").Select
Else
Rows("50:57").EntireRow.Hidden = True
Range("G48").Value = "Show"
ActiveSheet.Range("A1").Select
End If
End If
This will need to be repeated 10's of times as buttons are located at similar intervals down the sheet, so looping makes the most sense. Any help would be of great help as my attempts to combine the two functions have failed thus far.
Your code could be shortened to this
Private Sub Worksheet_Change(ByVal Target As Range)
Dim buttonRng As Range, hideRng As Range
Application.EnableEvents = False
Set buttonRng = Target
' Add in your ranges into this If statement
If Not Intersect(Target, Me.Range("G38")) Is Nothing Then
Set hideRng = Me.Rows("40:47")
ElseIf Not Intersect(Target, Me.Range("G48")) Is Nothing Then
Set hideRng = Me.Rows("50:57")
Else
Set hideRng = Nothing
End If
If Not hideRng Is Nothing Then
With hideRng
.Hidden = Not .Hidden
End With
buttonRng.Value2 = IIf(buttonRng.Value2 = "Show", "Hide", "Show")
End If
Application.EnableEvents = True
End Sub
You could add an additional sheet in with a list of the button location addresses and the range for them to hide.
You will need to set column B to text
and then use the following code
Private Sub Worksheet_Change(ByVal Target As Range)
Dim buttonRng As Range, hideRng As Range
Application.EnableEvents = False
Set buttonRng = Target
With Sheets("Button Hide Range").Columns(1)
Set hideRng = .Find(Target.Address(False, False))
End With
If Not hideRng Is Nothing Then
With Me.Rows(hideRng.Offset(0, 1).Value2)
.Hidden = Not .Hidden
End With
buttonRng.Value2 = IIf(buttonRng.Value2 = "Show", "Hide", "Show")
End If
Application.EnableEvents = True
End Sub
This sheet can then be hidden or set to xlVeryHidden if desired so it is not viewable by the end user.
Or if all of the rows to be hidden are the same offset away from the buttons you could use
Private Sub Worksheet_Change(ByVal Target As Range)
Dim buttonRng As Range
Dim i As Long
Application.EnableEvents = False
' i = row of first button to row of last button. Assuming each button is 10 rows apart from the previous
For i = 38 To 78 Step 10
If buttonRng Is Nothing Then
Set buttonRng = Me.Range("G" & i)
Else
Set buttonRng = Union(buttonRng, Me.Range("G" & i))
End If
Next i
If Not Intersect(Target, buttonRng) Is Nothing Then
' Assuming rows to be hidden are starts 2 rows away from button and ends 9 rows away
With Me.Rows(Target.Offset(2).Row & ":" & Target.Offset(9).Row)
.Hidden = Not .Hidden
End With
Target.Value2 = IIf(Target.Value = "Show", "Hide", "Show")
End If
Application.EnableEvents = True
End Sub

Excel VBA - Using shapes as toggle buttons

I'm trying to use a shape instead of a button to toggle hiding rows with blank cells (according to conditions). Is it even possible?
Sub ToggleChevron3_Click()
Dim rng As Range, cell As Range
Set rng = Range("A1:C100")
Application.ScreenUpdating = False
With rng
For Each cell In rng
If cell.Offset(0, 4).Value = "" Then ' Condition 1
If cell.Value = "" Then ' Condition 2
ActiveSheet.Shapes("Chevron 3").cell.EntireRow.Hidden _
= Not ActiveSheet.Shapes("Chevron 3").cell.EntireRow.Hidden
End If
End If
Next
End With
Application.ScreenUpdating = True
End Sub
Yes, it is possible. The code to accomplish what I think you are looking for is below. Both pieces of code below assume you want to just click a button to hide / unhide the rows, depending on the current state.
Sub ToggleChevron3_Click()
Application.ScreenUpdating = False
Dim rng As Range, cell As Range
'Set rng = Range("A1:C100") 'do you really want to loop through every cell in columns A through C
Set rng = Range("A1:A100")
For Each cell In rng
If Len(cell.Offset(, 4).Value) = 0 And Len(cell.Value) = 0 Then
Dim bToggle As Boolean
bToggle = cell.EntireRow.Hidden
cell.EntireRow.Hidden = Not bToggle
End If
Next
Application.ScreenUpdating = True
End Sub
However, there is alternative that is cleaner code and faster execution, as long as filtering is okay for you.
Sub ToggleChevron3_Click()
Application.ScreenUpdating = False
Dim bToggle As Boolean
bToggle = ActiveSheet.AutoFilterMode
If bToggle Then
ActiveSheet.AutoFilterMode = False
Else
Dim rng As Range
Set rng = Range("A1:E100") 'used E because you had an offset of 4 columns
With rng
.AutoFilter 5, "<>"
.AutoFilter 1, "<>"
End With
End If
Application.ScreenUpdating = True
End Sub

Resources