Error when referring to many multiple named ranges in Range property - vba
I have around 236 named ranges (columns) for a large table of data. I get this error when trying to split up the long code-line of delimited named ranges:
Run-time error '1004' Application-defined or object-defined error
E.g.:
Worksheets("Sheet1").Range("foo1,foo2" _
& "foo3,foo4" _
& "..." _
& "foo235,foo236")
I am trying to filter and unfilter columns based on specific criteria (named ranges). Everything seems to work fine (for smaller strings that only span 1 line in length) until I have to split the code into multiple lines since it reaches the end of the window..
Code -
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$B$3" Then
Worksheets("Sheet1").Range("Fruit," _
& "Months,Colour").EntireColumn.Hidden = Target.Value = "CustomView"
End If
If Target.Address = "$B$3" Then
Worksheets("Sheet1").Range("Colour,Number" _
& "Months").EntireColumn.Hidden = Target.Value = "Custom2View"
End If
End Sub
This code doesn't seem to work. I think it has something to do with the quotes and how excel reads it but i haven't been able to find a fix yet.
New code being tested based on suggestions in comments results in an error Run-time error '1004' Application-defined or object-defined error
Private Sub Worksheet_Change(ByVal Target As Range)
Dim arr, i As Long, rng As Range
If Target.Address = "$B$3" Then
arr = Split("foo1,foo2,foo3,...,foo266,foo267", ",")
Set rng = Worksheets("Database").Range(arr(0))
For i = 1 To UBound(arr)
Set rng = Application.Union(rng, Worksheets("Database").Range(arr(i)))
Next i
rng.EntireColumn.Hidden = (Target.Value = "CustomView")
End If
End Sub
You can use Application.Union to build up a range and then hide/show that range in one shot.
EDIT: based on your second shared file I think you need something like this. Your previous code was not checking the value of the "view name" cell and was applying all of the views, leaving you with the last one...
Eg:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim arr, q As Long, rng As Range, sht As Worksheet
Set sht = Worksheets("Database")
If Target.Address = "$B$3" Then
'unhide all columns forst
sht.UsedRange.EntireColumn.Hidden = False
Select Case Target.Value
Case "CustomView"
arr = Split("A,B,C_,X,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM," & _
"AN,AO,AP,AQ,AR,AS,AT,AV,AW,AX,AY,AZ,BA,BB,BC,BD,BE,BF,BG," & _
"BH,BI,BJ,BK,BL,BM,BN,BO,BP,BQ,BR,BS,BT,BU,BV,BW,BX,BY,BZ,CA," & _
"CB,CC,CD,CE,CF,CG,CH,CI,CJ,CK,CL,CU,CV,CW,CX,CY,CZ,DA,DB,DC", ",")
Case "XX100View"
arr = Split("D,E,F,G,X,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO," & _
"AP,AQ,AR,AS,AT,AV,AW,AX,AY,AZ,BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ," & _
"BK,BL,BM,BN,BO,BP,BQ,BR,BS,BT,BU,BV,BW,BX,BY,BZ,CA,CB,CC,CD,CE," & _
"CF,CG,CH,CI,CJ,CK,CL,CU,CV,CW,CX,CY,CZ,DA,DB,DC", ",")
Case "OtherView"
arr = Split("A,B,D,E,F,G,H,I,X,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM," & _
"AN,AO,AP,AQ,AR,AS,AT,AV,AW,AX,AY,AZ,BA,BB,BC,BD,BE,BF,BG,BH," & _
"BI,BJ,BK,BL,BM,BN,BO,BP,BQ,BR,BS,BT,BU,BV,BW,BX,BY,BZ,CA,CB," & _
"CC,CD,CE,CF,CG,CH,CI,CJ,CK,CL,CU,CV,CW,CX,CY,CZ,DA,DB,DC", ",")
End Select
If Not IsEmpty(arr) Then
Set rng = sht.Range(arr(0))
For q = 1 To UBound(arr)
Set rng = Application.Union(rng, sht.Range(arr(q)))
Next q
rng.EntireColumn.Hidden = True '<<edited
End If 'got a view
End If 'is view name cell
End Sub
PS - your range names don't need to include all of your data: a single cell would be fine, since you use EntireColumn to expand it to the entire sheet height anyway.
Related
Adding custom formula to Range() cell
Sub test() Application.DisplayAlerts = False Application.ScreenUpdating = False 'keeping the screen clean Sheets("Data").Select 'Here is where the error is triggered. With ThisWorkbook.Worksheets("TestSheet") '.Range("A2:A" & Lr).Formula = "=CusVlookup(Z2,Data'!A:B,2)" <- this doesnt work either .Range("A2:A" & Lr) = "=CusVlookup(Z2,Data'!A:B,2)" End With End Sub Function CusVlookup(lookupval, LookupRange As Range, indexcol As Long) Dim x As Range Dim Result As String Result = "" For Each x In LookupRange If x = lookupval Then Result = Result & "," & x.Offset(0, indexcol - 1) End If Next x CusVlookup = Result End Function I've tried using the regular Vlookup and works just fine but if I try to use this custom function it triggers the error. By the way I need to get the multiple matches "vlookups" into one cell separated by comma.(I added the goal just in case you know a better/faster way to do the same.) whats wrong with the code? Error 1004 - Application-defined or object-defined error
VBA Code for search box that filters table
I've designed a search box that filters my table when text is entered into said search box. The problem is that it is soooo slow, it's almost not even worth having it in my workbook right now. Can anyone think of any way to revise/improve upon this code? Here is my code currently: Private Sub TextBox1_Change() Dim searchArea As Range, searchRow As Range, searchCell As Range Dim searchString As String Dim lastRow As Integer Application.ScreenUpdating = False searchString = "*" & LCase(TextBox1.Value) & "*" Rows.Hidden = False lastRow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row Set searchArea = Me.Range("f3:f791", "f3" & lastRow) searchArea.EntireRow.Hidden = True For Each searchRow In searchArea.Rows For Each searchCell In searchRow.Cells If LCase(searchCell) Like searchString Then searchRow.Hidden = False Exit For End If Next searchCell Next searchRow Application.Goto Range("Z1"), True ActiveWindow.ScrollColumn = 1 Application.ScreenUpdating = True End Sub Edited my code to this: Private Sub TextBox1_Change() ActiveSheet.ListObjects("states").Range.AutoFilter Field:=1, _ Criteria1:="*" & [G1] & "*", Operator:=xlFilterValues End Sub However, this is not working. There are text and numbers in Field 1, and this only is filtering text, not the numbers...
This is definitely redundantly redundant, because your iteration is over a single column: For Each searchRow In searchArea.Rows For Each searchCell In searchRow.Cells '### searchRow ONLY HAS ONE CELL! This second/inner loop is totally unnecessary If LCase(searchCell) Like searchString Then searchRow.Hidden = False Exit For End If Next searchCell Next searchRow Rewrite as: For Each searchCell in searchArea.Cells '## Assumes searchArea is single column searchCell.EntireRow.Hidden = Not (LCase(searchCell) Like searchString) Next That alone should improve performance, but I think AutoFilter is a better method, and you should be able to derive the basic code for that from the Macro Recorder. This would look something like: searchArea.AutoFilter Field:=1, Criteria1:="=" & searchString, _ Operator:=xlAnd, Criteria2:="<>" This should filter to display only non-blank rows which contain your searchString #Yowe3k's points about the range assigment should also be noted, and you may use the AfterUpdate event of the TextBox instead of the Change event. UPDATE This might work to handle your mixed cases of numeric/text values. There might be a better way to do this but I don't see an obvious solution. The AutoFilter is meant to work with either text or numbers, but not both. So this attempts to convert numeric values to string representations. You may need to make changes elsewhere if the numeric values are referenced in formula, etc. Dim arr, v Dim tbl As ListObject Set tbl = ActiveSheet.ListObjects(1) ' ## Disable filter if it's on already If tbl.Range.AutoFilter Then tbl.Range.AutoFilter arr = tbl.DataBodyRange.Columns(1).Value ' ## Convert your range of mixed numeric/string to string For v = LBound(arr, 1) To UBound(arr, 1) If IsNumeric(arr(v, 1)) Then arr(v, 1) = "'" & CStr(arr(v, 1)) End If Next ' ## Put the string data back out to the worksheet tbl.DataBodyRange.Columns(1).Value = arr tbl.Range.AutoFilter Field:=1, _ Criteria1:="*" & CStr([G1]) & "*", Operator:=xlFilterValues
VBA excel - return the last matching value in a column using VBA
Basically, I have a rather large (and growing) sheet of position details and I'm looking to build in a sub routine that, once a position number is entered into the relevant cell, will auto-populate the corresponding cells in the row. VLOOKUP would do the trick nicely except, when a position has multiple lines, it returns the earliest set of details--I need it to return the latest. I can produce the answer I need using a LOOKUP function , but I can't seem to translate the function across to VBA. Example lookup function: LOOKUP(D17,1/($D$2:$D$10=D17),E2:E10) This is what I have so far Sub Worksheet_Change(ByVal Target As Excel.Range) If Target.Column = 4 Then actionrow = Target.Row resulte = Application.WorksheetFunction.Lookup(2, 1 / Range("D2:D10") = Target.Value, Range("E2:E10")) If Target.Value <> "" Then Range("E" & actionrow).formula = resulte End If End If End Sub
I think that looking at column D for a matching value with the Range.Find method would do. Start at the Target cell and use the SearchDirection:=xlPrevious option. Something will always be found. If the row it is found is not the same row as Target then use the value in column E to populate the cell right of Target. Private Sub Worksheet_Change(ByVal Target As Range) If Not Intersect(Columns(4), Target) Is Nothing Then On Error GoTo bm_Safe_Exit Application.EnableEvents = True Dim trgt As Range, lastrw As Long For Each trgt In Intersect(Columns(4), Target) lastrw = Columns(4).Find(what:=trgt.Value, after:=trgt, _ lookat:=xlWhole, SearchDirection:=xlPrevious).Row Debug.Print lastrw If lastrw <> trgt.Row Then trgt.Offset(0, 1) = Cells(lastrw, trgt.Column + 1).Value End If Next trgt End If bm_Safe_Exit: Application.EnableEvents = True End Sub This should survive pasting multiple values into column D.
You can use .Find function with parameter SearchDirection:=xlPrevious For case where you are searching word "AC" in a row 4: Set FindCell = sh_wb_SF.Range("4:4").Find(What:="AC", LookIn:=xlValues, SearchDirection:=xlPrevious) If FindCell Is Nothing Then MsgBox ("Ooooooopppps") End If
How do I get a cell's position within a range?
How would I go about getting the relative position of a cell within a range? Finding the position of a cell in a worksheet is trivial, using the Row- and Column-properties, but I am unsure of how to do the same within a range. I considered using the position of the top-left cell in the range I want to find the position of a cell in, and just deduct it (-1) from the position of the cell in the worksheet, but it gets a little bit cumbersome. Is there a more elegant way to go about this? My best attempt, including a test, so far is this: Option Explicit Sub test() Dim r As Range: Set r = Sheet1.Range("B2:E10") Dim c As Range: Set c = Sheet1.Range("C2") Debug.Print "Column in sheet: " & c.Column Debug.Print "Row in sheet: " & c.Row Debug.Print "Column in range: " & column_in_range(r, c) Debug.Print "Row in range: " & row_in_range(r, c) End Sub Function column_in_range(r As Range, c As Range) As Long column_in_range = c.Column - (r.Cells(1, 1).Column - 1) End Function Function row_in_range(r As Range, c As Range) As Long row_in_range = c.Row - (r.Cells(1, 1).Row - 1) End Function This gives the desired output: Column in sheet: 3 Row in sheet: 2 Column in range: 2 Row in range: 1 But I wonder if there are any native functions I can use instead?
updated using variant provided by lori_m But I wonder if there are any native functions ... use this Sub test() Dim r As Range, c As Range With Sheet1 Set r = .[B2:E10] Set c = .[C2] End With If Not Intersect(r, c) Is Nothing Then Debug.Print "Column in sheet: " & c.Column Debug.Print "Row in sheet: " & c.Row Debug.Print "Column in range: " & Range(r(1), c).Columns.Count Debug.Print "Row in range: " & Range(r(1), c).Rows.Count End If End Sub output Column in sheet: 3 Row in sheet: 2 Column in range: 2 Row in range: 1
There is no native way to do it. I also do what you have mentioned in the code above. However I put some extra checks. Sub test1() Dim r As Range: Set r = Sheet1.Range("B2:E10") Dim c As Range: Set c = Sheet2.Range("C2") '<~~ Changed Sheet1 to sheet2 Dim rng As Range On Error Resume Next Set rng = Intersect(c, r) On Error GoTo 0 '~~> Check if the range is in main range If Not rng Is Nothing Then ' '~~> Rest of your code ' Else MsgBox c.Address & " in " & c.Parent.Name & _ " is not a part of " & _ r.Address & " in " & r.Parent.Name End If End Sub
In my opinion there is almost native way to check it but result is a string required some additional manipulation. All you need to use is a proper construction of .Address property (according to MSDN). Some examples: Dim r As Range: Set r = Sheet1.Range("B2:E10") Dim c As Range: Set c = Sheet1.Range("c2") Debug.Print c.Address(False, False, xlR1C1, , r.Cells(0, 0)) '>>result: R[1]C[2] '----------------------------------------------------- Set c = Sheet1.Range("e2") Debug.Print c.Address(False, False, xlR1C1, , r.Cells(0, 0)) '>>result: R[1]C[4] '----------------------------------------------------- Set c = Sheet1.Range("e5") Debug.Print c.Address(False, False, xlR1C1, , r.Cells(0, 0)) '>>result: R[4]C[4] '-----------------------------------------------------
Take a look on MSDN to see more. You can use something like : MsgBox ActiveCell.Address(RowAbsolute:=True, _ ColumnAbsolute:=True, _ ReferenceStyle:=xlR1C1, _ External:=False, _ RelativeTo:=Range("B2")) 'Or shorter version : MsgBox ActiveCell.Address(, , xlR1C1, False, Range("B2")) But you'll have both information about row and column in the range, but not separately. So you'll still need to extract these values from the answer (look like : R18C20) in two functions, so almost the same issue...
I'm not totally sure if this is what you are after. But here it goes: Sub ts2() Dim test As Range Set test = Range("B2:E10") Dim topcorner As Range Dim testcell As Range Set topcorner = Cells(test.Row, test.Column) Set testcell = Range("D7") rel_row = testcell.Row - topcorner.Row rel_col = testcell.Column - topcorner.Column End Sub By this, you will find the relative position. But maybe you were looking for some built in function ? If this was not the thing you were after, please edit your post...
Create named range of all cells that contain constants or formulas?
I am trying to create a named range that refers to all cells containing formulas or constants. But I get an error message on the row that starts with Set r = Union(... How can I get this to work? Dim r As Range Set r = Union(Sheet1.Cells.SpecialCells(xlCellTypeConstants), Sheet1.Cells.SpecialCells(xlCellTypeFormulas), _ Sheet22.Cells.SpecialCells(xlCellTypeConstants), Sheet22.Cells.SpecialCells(xlCellTypeFormulas))
Union only works with Ranges that are on the same sheets. You can build a collection of the addresses like this though Sub Main() Dim arr As Variant arr = Array( _ GetAddresses(Sheet1, xlCellTypeConstants), _ GetAddresses(Sheet1, xlCellTypeFormulas), _ GetAddresses(Sheet2, xlCellTypeConstants), _ GetAddresses(Sheet2, xlCellTypeFormulas) _ ) Dim r As Variant For Each r In arr If Len(r) > 0 Then Debug.Print r Next End Sub Function GetAddresses(sh As Worksheet, cellType As XlCellType) As String On Error Resume Next GetAddresses = sh.Name & "!" & sh.Cells.SpecialCells(cellType).Address On Error GoTo 0 End Function If you need to handle your errors differently, have a look at this answer