sub declaration visual Basic - vba

I am really new with vba, so please forgive my slaughtering of the code. I'm trying to write a macro for excel (my first one), and I get "statement invalid outside of type block" (pointing at the first line). Here is my code:
Sub MakeHTMLTable()
Worksheets("Sheet1").Activate
endRow As Integer
For Count = 1 To 200
For CountY = 1 To 200
If (!ActiveSheet.Cells(Count, CountY).Value.IsEmpty) Then
ActiveSheet.Cells(Count, CountY).Value = "<td>" + ActiveSheet.Cells(Count, CountY).Value + "</td>"
End If
Exit For
Exit For
For i = 1 To 200
If (!ActiveSheet.Cells(i, 1).Value.IsEmpty()) Then
ActiveSheet.Cells(i, 1).Value = "<tr>" + ActiveSheet.Cells(i, 1)
End If
Exit For
For x = 1 To 200
If (!ActiveSheet.Cells(x, 1).Value.IsEmpty()) Then
endRow = x
End If
Exit For
For countAgain = 1 To 200
If (!ActiveSheet.Cells(x, countAgain).Value.IsEmpty()) Then
ActiveSheet.Cells(x, countAgain).Value = ActiveSheet.Cells(x, countAgain).Value + "</tr>"
End If
Exit For
End Sub
I really don't understand, as the debugger fails on the line of computer generated code without even making it to mine. Have I missed ending an If" or For block?
I also realize that I'm probably reinventing the wheel. Any help on more appropriate built in functions would be appreciated.

It looks like you've got quite a few syntax errors in your code.
In VBA, local variables are declared with the Dim keyword.
So, the endRow declaration should look like this:
Dim endRow As Integer
For loops should end with the Next statement. So, your For loops should look like this:
For x = 1 To 200
If (!ActiveSheet.Cells(x, 1).Value.IsEmpty()) Then
endRow = x
End If
Next
VBA uses the keyword Not instead of !, so, your conditionals should look like this:
If (Not (ActiveSheet.Cells(i, 1).Value.IsEmpty())) ...
Try removing most of the code and adding it back in line-by-line until all of it works. The VBA syntax can be cumbersome for those who aren't used to it.

Related

Application or object defined error Runtime error 1004

I have created the following code to extract information from an excel table. But I am getting an error exactly at the if statement. I have even tried executing the code from a module and even from the worksheet level. I have read about this issue and it seems that selecting the sheet seems to be the main problem, but I have also tried but in vain I can't seem to find a solution. It would be really great if someone could help me with this. Thank you in advance.
Sub test()
Dim row As Double, col As Double, inc As Double
row = 2
col = 2
inc = 20
'Sheets("sche").Range("a1").Select
For row = 2 To 15
For col = 2 To 52
If (Cells(r, c).Font.Bold Or Left(Cells(r, c).Value, 2) = "BP") Then 'Error is happening here
Sheets("sche").Cells(inc, 2).Value = Sheets("sche").Cells(r, c).Value
inc = inc + 1
GoTo zone
Else: GoTo zone
End If
zone:
Next col
Next row
End sub
You have declared row and col as variables but are using r and c in your If...Then block.
A prime example of why you should add Option Explicit at the top of every module to prevent typo's and using undeclared variables.
I've adjusted your code and tested it OK:
Note: I removed the Else condition and GoTo Zone as they were redundant in your code (at least in the example you provided). Also although not a cause of your error it's not necesarry to encapsulate your entire If...Then condition in parentheses.
Sub test()
Dim row As Double, col As Double, inc As Double
row = 2
col = 2
inc = 20
'Sheets("sche").Range("a1").Select
For row = 2 To 15
For col = 2 To 52
If Cells(row, col).Font.Bold Or Left(Cells(row, col).Value, 2) = "BP" Then 'Error is happening here
Sheets("sche").Cells(inc, 2).Value = Sheets("sche").Cells(row, col).Value
inc = inc + 1
End If
Next col
Next row
End Sub
I've changed this:
If Cells(r, c).Font.Bold Or Left(Cells(r, c).Value, 2) = "BP" Then 'Error is happening here
Sheets("sche").Cells(inc, 2).Value = Sheets("sche").Cells(r, c).Value
To this:
If Cells(row, col).Font.Bold Or Left(Cells(row, col).Value, 2) = "BP" Then 'Error is happening here
Sheets("sche").Cells(inc, 2).Value = Sheets("sche").Cells(row, col).Value
Furthermore, it's good practice to expicitly reference your objects.
This is because, for example, the implicit reference for the Cells() property is the Active Worksheet:
Using this property without an object qualifier returns a Range object that represents all the cells on the active worksheet.
This can cause unexpected results if for example, you run your code whilst a different sheet than desired is active or a user changes worksheets during the codes execution.
It would be better to write the code like:
If Sheets("sche").Cells(row, col).Font.Bold Or Left(Sheets("sche").Cells(row, col).Value, 2) = "BP" Then
The With statement can come in handy to shorten the written code when making many references to the same objects, like workbooks, worksheets and/or Ranges etc. You can read about it in the documentation.

VBA - Struggling with worksheet_change. Not working with no error given

I have a sheet in which our wholesale team are to enter L09 Part Codes and quickly see how much we have in stock of that item. The problem is that new starters may struggle to learn these part numbers as they don't follow a simple rule. What I did was create an easier code to remember which is simply: "Cable Type" & "Core Size" & "Cut Length", they also have the option to add "Colour" and "Brand" separated by spaces.
Their entered string may look like 6242y 2.5 100, or maybe 6242y 2.5 100 Grey, etc. and so where to look in my mapped table for what they've written depends on how many terms they put in. As you can see from the attached picture I need to select the correct column to look in for their code, and then offset back a few columns to suggest the correct L09 Part Number.
I hope the context makes a bit of sense and helps with the below code. The idea was for a new starter to enter something simple and it be replaced before their very eyes...
If anyone could help me to correct the following it would be greatly appreciated:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim P, Products, S, Search As Range
Dim Column As String
Dim Counter As Integer
Dim Spaces As Long
'On Error Resume Next
Counter = 0
'For top table only
If Target.Column = 1 And Target.Row < 100 Then
'Count spaces
Spaces = UBound(Split(Target, " "), 1)
Select Case Spaces
Case Is = 2
Column = "M"
Case Is = 3
Column = "O"
Case Is = 4
Column = "Q"
End Select
'When string has spaces
If Spaces <> 0 Then
'Set simple code range
Set Search = Sheets("Cherries").Range(Column & 1 & ":" & Column & 10000)
For Each S In Search
If S = Target Then
Target = S.Offset(0, 3 - 2 * Spaces)
End If
Next S
End If
Set Products = Sheets("Order Entry").Range("A3:A99")
For Each P In Products
If P.Value <> "" Then
Counter = Counter + 1
End If
Next P
Sheets("Order Entry").Rows("3:" & Counter + 11).Hidden = False
Sheets("Order Entry").Rows(Counter + 11 & ":99").Hidden = True
End If
End Sub
Unfortunately I'm not sure which line is erroring as no error message is given.
Thank you for your time.

Concatenated string is not recognized by my Sub

I made the following Sub to help me copy values from other workbooks or even just from other sheets within the same workbook.
Private Sub CopyValues(fromSheet As String, fromRange As String, toSheet As String, toRange As String, Optional fromFileName As String = "")
Dim toFile As Excel.Workbook
Set toFile = ActiveWorkbook
Dim fromFile As Excel.Workbook
If Len(fromFileName) > 0 Then
Set fromFile = Workbooks.Open(fromFileName)
Else
Set fromFile = ActiveWorkbook
End If
With ActiveWorkbook
toFile.Sheets(toSheet).Range(toRange).Value = fromFile.Sheets(fromSheet).Range(fromRange).Value
End With
If Len(fromFileName) > 0 Then
fromFile.Close savechanges:=False
End If
End Sub
It works pretty well (and you all are free to use it if you find it helpful). Below is an example of code that works:
Call CopyValues(reportName, "B4:C15", reportName, "E2:F13", reportDirPath)
Unfortunately, I'm having trouble with a specific case. I'm looking to copy the same value into multiple cells in the same column. Below is what I came up with:
For i = 2 To i = 13
Call CopyValues(reportName, "AJ2", reportName, "H" + i, reportDirPath)
Next i
That didn't work. No error messages, but none of the values were pasted into my sheet. I thought that maybe concatenating the integer i was converting (is that the technical word?) the string to a different type, so I tried the following:
For i = 2 To i = 13
Call CopyValues(reportName, "AJ2", reportName, CStr("H" + i), reportDirPath)
Next i
That still didn't work. Same deal. No error messages, but none of the values were pasted into my sheet.
Changing the + to an & also didn't work:
For i = 2 To i = 13
Call CopyValues(reportName, "AJ2", reportName, CStr("H" & i), reportDirPath)
Next i
Obviously, I could just write out each individual case, but that seems kind of ridiculous. Any idea what's going on?
When I tried your code your 'For' loops were not working, but after I changed your for loop to say 'For i = 2 to 13' as opposed to 'For i=2 To i = 13' the last version of your code worked for me.
For i = 2 To 13
Call CopyValues("Sheet1", "A1", "Sheet2", CStr("J" & i))
Next i
End Sub
So I think that could have been your trouble.

Referencing Multiple Sheets with large sets of Data

I am fairly new to VBA and having some general obstacles with basic syntax. I am using the below code to trim leading spaces and color code an ActiveSheet I am currently working on.
I have another Worksheet called "Country" that I would like to apply the same logic to the current sheet I am using. I am also having difficulties using the most efficient code to find any cells with values of "AcctTotal" , " CurrTotal" and " BravoTotal" (there are about 14,000 rows of data). I am currently highlighting the whole spreadsheet and utilizing "UsedRange" to find these cells.
To sum it up:
I would like to trim leading spaces and color code any values of "AcctTotal" , " CurrTotal" and " BravoTotal" in two worksheets: "Currency" and "Country"
Sub ColorCodeCurrency()
Dim r As Range
For Each r In Selection
If r.Value = " AcctTotal" Then
r.Value = LTrim(r.Value)
Intersect(r.EntireRow, ActiveSheet.UsedRange).Interior.ColorIndex = 15
End If
Next r
Dim s As Range
For Each s In Selection
If s.Value = " CurrTotal" Then
s.Value = LTrim(s.Value)
Intersect(s.EntireRow, ActiveSheet.UsedRange).Interior.ColorIndex = 40
End If
Next s
Dim t As Range
For Each t In Selection
If t.Value = " BravoTotal" Then
t.Value = LTrim(t.Value)
Intersect(t.EntireRow, ActiveSheet.UsedRange).Interior.ColorIndex = 35
End If
Next t
End Sub
Most of the problem is that you're doing the same thing three times. The 'For Each' statement is going through every cell three times. If you joined it into
for each r in selection
if r.value ="AcctTotal" then
'do something
elseif r.value = "CurrTotal" then
'do something else
elseif r.value = "BravoTotal" then
'do the third thing
end if
In addition to what Maudise said, when you refer to your data, you can use syntax like:
Sheets("Country").Range("A1:E14000")
If it's possible to make changes to your source data, you may find it helpful to format it as a table for easy reference. Use the Name Manager to give the table a useful name. Then, you can say something like:
For Each r In Sheets("Country").Range("CountryTable")
You could try this way:
Public Sub ColorCode ()
Dim i As Integer, j As Integer, m As Integer, n As Integer
i = Range("A:A").End(xlDown).Row
j = Cells.End(xlToRight).Column
For m = 1 To i
For n = 1 To j
If Cells(m, n).Value < 50 Then
Cells(m, n).Interior.ColorIndex = 13
End If
Next n
Next m
End Sub
One solution is to call this code placed in a module into "This workbook" in "Private Sub Workbook_Open()".

If ElseIf And Or functions VBA

I have a really long IF AND OR formula that I'm trying to convert to VBA so it's quicker.
=IF(OR(H10<>"GL402",H10<>"GL412",H10<>"GL422",H10<>"GL432",H10<>"GL442",H10<>"GL452",H10<>"GL492",
H10<>"GL480",H10<>"GL370",H10<>"GL380",H10<>"GL710")*AND(OR(D10<>3,D10<>9,D10<>10),E10<>"ASX",
F10<>"AUD"),"F126",(IF(OR(H2="GL402",H2="GL412",H2="GL422",H2="GL432",H2="GL442",H2="GL452",H2="GL492")*
AND(OR(D2<>"3",D2<>"9",D2<>"10"),E2="ASX",F2="AUD"),"D111",.......))
I thought this should look like:
IF range("H10").Value <>""GL402"" or ""GL412"" or ""GL422"" or ""GL432"" or ""GL442"" _
or ""GL452"" or ""GL492"" or ""GL480"" or ""GL370"" or ""GL380"" or ""GL710"" AND _
range("D10").Value <>3 or 9 or 10 and range("E10").Value <>""ASX"" and _
range("F10").Value <>""AUD""
then
range("I10").Value = ""F126""
elseif
Range("H2").Value = ""GL402"" Or ""GL412"" Or ""GL422"" Or ""GL432"" Or ""GL442"" Or ""GL452"" Or ""GL492"" _
And Range("D2").Value <> 3 Or 9 Or 10 And Range("E2").Value = ""ASX"" And Range("F2").Value = ""AUD""
then
Range("I2").Value = ""D111""
elseif
another lengthy conditions with ANDs and ORs
plus I was hoping to loop this so it applies this whole IF formula until the value of cell A (whichever row) is blank.
I sort of know the loop should be
Do .........
next (with something like A1 + 1)
until A1 + 1 = ""
loop
any help appreciated!
The first rule of good code is that it should be clear - easy to read and debug. Only afterwards do you try to make it "fast". Converting your current expression to VBA may give a speed advantage but you still don't meet the first test...
You can make things cleaner with an expression like this (you can put this right in your spreadsheet):
=ISERROR(MATCH(H10,{"GL402","GL412","GL422","GL432","GL442","GL452","GL492","GL480","GL370","GL380","GL710"},0))
This will evaluate to "true" if the the value in H10 does not match any of the values in the array.
When you have a lot of or conditions in parallel, you can basically stop when the first condition is true.
An expression like that can be written in VBA as follows:
Sub test()
Dim matchStrings
Dim match1, match2
matchStrings = Array("GL402", "GL412", "GL422", "GL432", "GL442", "GL452", "GL492", "GL480", "GL370", "GL380", "GL710")
firstPart = Application.Match(Range("H10"), matchStrings, 0)
If IsError(firstPart) Then
MsgBox "no match found"
Else
match1 = true
MsgBox "match found at index " & firstPart
End If
End Sub
You can repeat similar code with other expressions, building match2, match3, etc - then combining with all the And and Or that you would like - for example
If match1 And (match2 Or match3) Then
... do something
Else
... do something else
End If
This won't work as expected:
If x = 1 Or 2 Or 3 Then
MsgBox "x is either 1, 2, or 3"
End If
because 2 and 3 aren't boolean (true/false) conditions (at least not the way you expect them to be).
The proper syntax is:
If x = 1 Or x = 2 Or x = 3 Then
MsgBox "x is either 1, 2, or 3"
End If
This is only a partial answer that nevertheless does address one of the many issues in your code.