I am tearing my hair out on this one.
I am trying to add the value from a userform textbox to a table.
However Excel is constantly crashing on me as soon as it runs the code below.
The error message i get is
runtime error -2147417848 "Method 'Value'of object 'Range' failed
then excel crashes
I have tried Option explicit to check i wasnt missing a variable or it was declared incorrectly, i have tried deleting the table and starting again, i have started a new workbook, i have change the table name, i have tried 4/5 different methods of adding the data to the table (Simple range offset, databodyrange(X,1), resizing the table etc). All crash when adding the value (which by the way is just text like mike/harry etc)
The workbook, has about 10 forms and they all work perfectly (they add data to tables etc), it is just this one causing issues
If i manually add data to the table it auto extends and have no issues
any help is appreciated.
Sub Enterprise_Update()
Dim lst As ListObject
Set lst = Sheets("Data Labels").ListObjects("Enterprises")
For Each ctrl In Enterprise_Setup.Controls
If ctrl.Name Like "Enterprise Name Value 1*" Then
z = z + 1
End If
Next ctrl
With lst.Sort
.SortFields.Clear
.Apply
End With
With lst
LstRw = .ListRows.Count
End With
Select Case LstRw
Case Is = 1
lst.DataBodyRange(LstRw, 1).Offset(1, 0).Value = Enterprise_Setup.Controls("Enterprise Name Value 1" & x)
Case Else
For x = 1 To z
sLookFor = CStr(Enterprise_Setup.Controls("Enterprise Name Value 1" & x))
Set oLookin = lst.DataBodyRange
Set oFound = oLookin.Find(what:=sLookFor, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True)
If Not oFound Is Nothing Then
GoTo err:
Else
With lst
LstRw = .ListRows.Count
End With
End If
r = Enterprise_Setup.Controls("Enterprise Name Value 1" & x).Value
Sheets("Data Labels").Select
Range(lst.Range.Cells(1).Address).End(xlDown).Offset(1, 0).Select
ActiveCell.Value = r
'lst.DataBodyRange(X).Value = r
err:
Next
End Select
With lst.Sort
.SortFields.Clear
.SortFields.Add Key:=Range("Enterprises[Enterprises]"), Order:=xlAscending
.Header = xlYes
.Apply
End With
End Sub
I'm looking at this portion of your code and have some comments on it.
If Not oFound Is Nothing Then
GoTo err
Else
LstRw = Lst.ListRows.Count
End If
r = Enterprise_Setup.Controls("Enterprise Name Value 1" & x).Value
Sheets("Data Labels").Select
Range(Lst.Range.Cells(1).Address).End(xlDown).Offset(1, 0).Select
ActiveCell.Value = r
For one, GoTo err? Err is VBA's error object. VBA is very good at avoiding errors from intrusions on its naming prerogative but I still think its asking for trouble. Note that the final colon is required to identify the label but not the destination statement.
Using labels to jump back and forth in the code isn't good practice. Nor is it needed in this case. A simple If Not oFound Is Nothing Then should do the job if you extend the End If to the point where you have the label. Anyway, what's the point of LstRw = Lst.ListRows.Count? You took that measure before the Select Case statement. Has it changed?
But most of all, I question why you would jump if you found what you were looking for and process when you didn't. This is the best candidate for the error you see.
Selecting another sheet is not good practice and not required, either. You can read from and write to the sheet without selecting it. If you are selecting the sheet from a user form Excel might consider this cause for divorce. Of course, selecting a cell is equally unnecessary.
Range(Lst.Range.Cells(1).Address).End(xlDown).Offset(1, 0) probably works, although I think it's adventurous. But selecting that cell may be problematic when done from within a user form. The form sort of claims right of first attention. I doubt that you can activate that cell from where you are.
You can write to it, however. Sheets("Data Labels").Cells(54, "A").Value = r would be a great success, I feel confident. The contortions you undertake to describe the cell's coordinates aren't necessary. The column seems to be Lst.Range.Column and the row would be Lst.Range.Row + LstRw or perhaps Lst.DataBodyRange.Row + LstRw.
However, there might be additional problems resulting from the location of the cell in a table or just under a table where adding a row might create conflict with data existing there. If the table is required to expand as a result of writing to that cell Excel would normally just over-write whatever might exist but it's a point worth considering if all other options have been exhausted.
I hope this analysis will help you find and correct the error.
I solved the issue by a less than pretty way. I managed to extend the table, and code around the blank rows, ie count none blanks, dynamic named ranges etc
Related
I have several worksheets that have a Control Button that is assigned the same macro. I need the macro to only work on the worksheet that it is on. It is currently sending me back to the first worksheet when I click on these buttons, regardless of which worksheet I am on. I am new to VBA so I am having a hard time understanding all of the macro, but mainly I don't understand the Application.Goto line and think that is where my trouble is. This code is written by someone else, but I am only trying to reverse-engineer / fix it for my own use. I have no idea why it is using the reference of "FirstTime". It is not one of the names of the worksheets or excel filename.
Sub Break()
Application.Goto Reference:="FirstTime"
Do Until ActiveCell = ""
If ActiveCell <> "" Then
ActiveCell.Offset(1, 0).Select
End If
Loop
If ActiveCell.Offset(0, -1) = "" Then
ActiveCell.Offset(0, -4).Select
ActiveCell.FormulaR1C1 = InputBox("Enter client engagement")
ActiveCell.Offset(0, 3).Select
ActiveCell.FormulaR1C1 = Now()
Else
ActiveCell.FormulaR1C1 = Now()
ActiveCell.Offset(0, -2).Select
ActiveCell.FormulaR1C1 = InputBox("Work performed/tasks completed")
End If
Range("A1").Select
End Sub
I've tried using other strings or removing any Reference from Application.GoTo, but it only gives me a 1004 error. It also seems to need this line, otherwise it also causes an error. The rest of the code/macro works as intended as far as I can, it's just a matter of going to the wrong worksheet when the Control Button is clicked.
I think you exactly understood your own problem by yourself.
When you execute Application.Goto Reference:="FirstTime", it goes to the range that was named FirstTime, which most likely in what you call "the first worksheet".
On the left of the formula bar, as shown in the screenshow below, you have a dropdown, you can use it to check the name.
If I am right so far, follow this procedure:
In the sheet where you want your macro to apply, select the range you want to call FirstTime.This range should most likely cover as many rows/columns as the one you should have spotted with my instructions above (it may even be the very same address).
Go to menu Formula > Name manager.
Click New.
Fill the window with:
Name = FirstTime
Scope = The worksheet you are currently on.
Refers to = The range you have selected (the worksheet on that range is expected to be the same as for field Scope).
This will make it so the new name you are defining has higher priority when executing Application.Goto.
Hoping someone can help – I expect there is something very simple that I am doing wrong.
The situation is this:
I have a table with variable rows (month to month)
Four columns where the one I am trying to place the formula in (CaseLink) is blank
Sample Table
The column ‘System’ has one of three values; CSv1, CSv2, PIA
The Case # column will have numbers – no repetition or consistency
The CaseLink column is where I am having the issue – I am trying to insert one of three hyperlinks to include the value in the Case # column. The link target is based on the value in the System column
Previously I only had two variables in the System column and was able to solve for with a simple IF statement as it was either true or false. Now with a third variable, I am having difficulties with the If / ElseIF format. Here is what I have tried:
Original if statement that works:
Range("C2").Select
ActiveCell.FormulaR1C1 = _
"=IF(RC[-2]=""CSv1"",HYPERLINK(CONCATENATE(""https://open. cloudav.com/servicedeliverdo.aspx?rdx=9992956J43211&conv="",RC[-1]),RC[-1]),HYPERLINK(CONCATENATE(""https://open.topcloudav.com/ha2servicedeliverdo.aspx?conv="",RC[-1]),RC[-1]))"
Range("D3").Select
Option 1: (this returns an error: Sub or Function not defined on Concatenate)
Range("C2").Select
If ActiveCell.Offset(0, -2).Value = "CSv1" Then Hyperlink (CONCATENATE("https://open.cloudav.com/servicedo.aspx?rdx=9992956J43211&conv="),RC[-1]),RC[-1]))
ElseIf ActiveCell.Offset(0, -2).Value = "CSv2" Then Hyperlink (CONCATENATE("https://open.cloudav.com/topservicedo.aspx?conv="),RC[-1]),RC[-1]))
ElseIf ActiveCell.Offset(0, -2).Value = "PIA" Then Hyperlink (CONCATENATE("https://dev.devroot.net/browse/PIA-"),RC[-1]),RC[-1]))
End If
Range("D3").Select
Option 2: (this returns an error indicating ElseIF is undefined
Range("C2").Select
ActiveCell.FormulaR1C1 = _
"IF(RC([-2])) = ""CSv1"" Then Hyperlink (CONCATENATE(""https://open.cloudav.com/servicedo.aspx?rdx=9992956J43211&conv="", RC[-1]), RC[-1])))"
elseif_
ActiveCell.FormulaR1C1 = _
"IF(RC([-2]) = ""CSv2"" then Hyperlink (CONCATENATE(""https://open.cloudav.com/topservicedo.aspx?conv="", RC[-1]), RC[-1])))"
elseif_
ActiveCell.FormulaR1C1 = _
"IF(RC([-2]))= ""PIA"" Then"
Hyperlink (concatenate("https://dev.devroot.net/browse/PIA-", (RC([-1])), (RC([-1]))))
End If
Range("D3").Select
I have also tried ActiveCell.Offset rather than ActiveCell.Formula with similar failure results
Any thoughts?
There a lot of thing that could be improve in your code:
Use variable instead of hard code
do not select
Indent better
I tried to replicate what you were doing,
Sub hyperlink()
Dim firstcellrow As Long ' First row where your code acts
Dim systemcellcollumn As Long ' Column w the system entries
Dim linkcollumn As Long ' Column where you want to link stuff
firstcellrow = 1 ' In my case
systemcellcollumn = 2 'From your image
linkcollumn = 4 'From your image
Dim activecellrow As Long ' Its a long name but thats actualy just a counter
Dim system As String ' Not needed if u use cell.text directly into select case
Dim i As Long
For i = 0 To 2 ' 0 to whatever you want
activecellrow = firstcellrow + i
system = Worksheets("test").Cells(activecellrow, systemcellcollumn).Text ' Not necessary, see comment under "Select Case"
Select Case system
' or Select Case Worksheets("test").Cells(activecellrow, systemcellcollumn).Text
Case "CSv1"
Cells(activecellrow, linkcollumn).FormulaR1C1 = "=IF(RC[-2]=""CSv1"",HYPERLINK(CONCATENATE(""https://open. cloudav.com/servicedeliverdo.aspx?rdx=9992956J43211&conv="",RC[-1]),RC[-1]),HYPERLINK(CONCATENATE(""https://open.topcloudav.com/ha2servicedeliverdo.aspx?conv="",RC[-1]),RC[-1]))"
Case "CSv2"
'etc
Case "PIA"
'etc
End Select
Next
End Sub
This code may not be perfect but is already more general and works
I appreciate all the comments - I am not a professional coder - This is something I am trying to get done by learning from everyone else. If this is not a forum where someone can go to ask for help without getting blasted for style, I apologize for wasting your time.
I did figure out a simple method of getting this done on my own in a single nested IF statement:
Range("C2").Select
ActiveCell.FormulaR1C1 = _
"=IF(RC[-2]=""CSv1"",HYPERLINK(CONCATENATE(""https://open.cloudav.com/deliverdo.aspx?rdx=9992956J43211&conv="",RC[-1]),RC[-1]),IF(RC[-2]=""CSv2"",HYPERLINK(CONCATENATE(""https://open.cloudav.com/topdeliverdo.aspx?conv="",RC[-1]),RC[-1]),IF(RC[-2]=""PIA"",HYPERLINK(CONCATENATE(""https://dev.devroot.net/browse/PIA-"",RC[-1]),RC[-1]))))"
Range("A2").Select
I'm struggling with what I believe is a loop problem. I'm more of a "backyard mechanic" with Excel VBA so please excuse my simple question.
I can't share the workbook due to proprietary information unfortunately but I have the code I use with some field name changes.
Background: I have a column that I take 1 cell at a time and feed it into a pivot table field and run reports. The way I have it now, I delete the current Row which returns the reference back to cell A2. Think of it like a programming Pez dispenser. Awful and very brute force I know. The row delete operation takes a lot of system resources and I'd like to optimize it. I've tried reading through here and a few other websites for the past couple hours but I can't make heads or tails of what I'm coming across.
Any help would be very greatly appreciated!
Sub AutoReport()
Dim strPage As String
Worksheets("HomePage").Select
Beginning:
'Sets the name in Home Page to the name in Feederlist cell F2
With Sheet1
strPage = Worksheets("FeederList").Range("A2")
Worksheets("HomePage").PivotTables("PivotTable1").PivotFields("UNIQUE ID"). _
CurrentPage = strPage
End With
**Do a Bunch of Stuff**
' Feeds the next input into the machine
MoveToNext:
Worksheets("FeederList").Activate
Worksheets("FeederList").Range("A2").EntireRow.Delete
If Worksheets("FeederList").Range("A2") = "" Then
MsgBox "All Reports have been created.", vbInformation + vbOKOnly
Exit Sub
Else
GoTo Beginning
End If
End Sub
the acceptance is the first step to learning. In general, the stackoverflow community encourages to invigorate the technical and logical parts of the brain by providing the hints to solution and not the exact solution. However, as you are very new, I am starting with giving off hints and later on the code to rectify your issue. You are going very well with your code, however some minor tweaks will optimize your code significantly.
Worksheets("HomePage").Select
Dim lstRow As Long
Dim rngCell As Range
Dim rngSelection As Range
'Let's find the last row with data in column A.
'So that we only traverse the required range without the need of
'deleting previous cells while using the For loop.
lstRow = Worksheets("FeederList").Range("A" & Application.Rows.Count).End(xlUp).Row
Set rngSelection = Worksheets("FeederList").Range("A2:A" & lstRow)
For Each rngCell In rngSelection.Cells
'Ignore all the cells with blank value or else the pivot table will throw the error
If Trim(rngCell.Value) <> vbNullString Then
'Sets the name in Home Page to the name in Feederlist cell F2
strPage = rngCell.Value
Worksheets("HomePage").PivotTables("PivotTable1").PivotFields("UNIQUE ID"). _
CurrentPage = strPage
' **Do a Bunch of Stuff**
End If
Next
rngSelection.Clear ' Optional - if the range really needs to be cleared
MsgBox "All Reports have been created.", vbInformation + vbOKOnly
You need to understand the changes and ask any further questions that you might have. Below are the changes made to the original code.
Introduced calculation of last cell in Column A having some data
Introduced For Loop instead of using labels eliminating the need of deleting rows
I'm trying to build a formula:
=BDS(Bonds!J2& " ISIN","ISSUE_UNDERWRITER","Headers","Y")
In one sheet that takes a unique identifier from another table.
These formula builds me a table. After it builds me the table, I need to take the next row in the other sheet:
=BDS(Bonds!J3& " ISIN","ISSUE_UNDERWRITER","Headers","Y")
Then insert that formula a the end of the previous table built by the previous formula.
What I tried was getting the last row and then offsetting it by one, but I'm trying to figure out how to loop through it.
This is what i have tried:
Sub Formula2()Formula2 Macro
Range("A1").Select
ActiveCell.FormulaR1C1 = _
"=BDS(Bonds!R[1]C[9]& "" ISIN"",""ISSUE_UNDERWRITER"",""Headers"",""Y"")"
lRow = Cells(Rows.Count, 1).End(xlUp).Select
Selection.Offset(1, 0).Select
ActiveCell.FormulaR1C1 = _
"=BDS(Bonds!R[-53]C10& "" ISIN"",""ISSUE_UNDERWRITER"",""Headers"",""Y"")"
Range("A57").Select
End Sub
Image of Table, Im trying to iterate through the ISIN Column. It is column "J"
Although selection and .select are used by the macro recorder, they cause big problems when developing code. It's worth your time to learn how to replace them with range objects. So, while I'm not directly answering your question, I'm trying to give you the tools to do so.
I've shown an example below to illustrate (although I do not work with the BDS() function so I'm undoubtedly getting the details wrong). The main point is that if you learn to move around using the range object you'll be much better off.
Sub formula()
Dim r As Range, sh As Worksheet, bondR As Range, bondSh as Worksheet
set sh = ActiveSheet
set r = sh.range("A1")
Set bondSh = Worksheets("Bonds")
Set bondR = bondSh.Range("J1")
For i = 1 To 10
r.formula = "=BDS(bondR.offset(i,0) & "" ISIN"",""ISSUE_UNDERWRITER"",""Headers"",""Y"")"
Set r = r.Offset(i, 0)
Next i
End Sub
Here I'm defining one range object, r, to track the location on the active sheet, and another, bondR, for the location on the "Bonds" sheet. Once the initial locations of these ranges are defined, you can manipulate them using the .offset(row,col) function as I've done with the simple for-loop, moving down 1 row (but 0 columns) in each loop.
Feel free to ask questions.
I'm still very new to using VBA, so I apologize if I don't know all of the preferred terms.
I am attempting to write a userform to populate a spreadsheet allowing me to track employees PTO used. This spreadsheet is the X-axis (row 1) being the date and the Y-axis (column A) being the employee name.
The userform I've created has 5 pieces of criteria:
1) Employee Name (ComboBox1; this is a drop down of multiple rows)
2) Date of PTO (ComboBox2; this is supposed to be a drop down of multiple columns)
3) Duration of PTO (OptionButton1 is 1 Day, OptionButton2 is 0.5 Day)
4) Enter Data (CommandButton1)
5) Cancel (CommandButton2)
I've completed criterion 1 by selecting and labeling the menu on the spreadsheet.
The rest is what's kicking me.
I cannot seem to get the dates (criterion 2), while in row format, to show up in the ComboBox2 drop down. If I transpose these items into a single column, I have been able to label the group and create the drop down menu. This is problematic as I will not be able to form a grid to populate.
My OptionButton1 and OptionButton2 items are intent to be the input values (1 and 0.5). At this time, I've been unable to give them values, simply names. This input is secondary to the major issue where I cannot get the grid format to work (paragraph above this).
The tertiary problem is the combination of criterion 4 and 5. My script is failing to execute CommandButton1, though I believe it's due to my extremely basic code:
Private Sub CommandButton1_Click()
cmdOK
End Sub
CommandButton2 appears to work using this code:
Private Sub CommandButton2_Click()
cmdCancel
End Sub
My end all be all question, having described my issues, would be "Is my end goal possible?" I only intend to use Excel for this, as many people already have access to it. If this is possible, then I would ask for either help identifying my error points and correcting, or a link to a coding manual where I can attempt to learn more about the functions (this is more of a long-term situation, which doesn't quite help the issue, but I would feel okay with).
Thank you in advance for responses.
Edit:
# Seth
I've made it as far as ComboBox2 (the dates) selection. I cannot get the loop, suggested below, to access the values (1 row, 365 columns).
I tried modifying the code from Seth, but I really don't know anything about loops; I feel I most likely did not fill out a section appropriately (I'm looking at .Value <> ""):
Private Sub ComboBox2_Change()
Dim i As Long
i = 1
Do While ThisWorkbook.ActiveSheet("Breakdown").Cells("A1:NC1", i).Value <> ""
Me.ComboBox1.AddItem (ThisWorkbook.ActiveSheet("Breakdown").Cells("A1:NC1", i).Value)
i = i + 1
Loop
End Sub
Using this code, I get the error "Run-time error '438': Object doesn't support this property or method"
I'm trying to find a general guide to understanding writing a loop, though I find no reference to some of the above statements, so I'm not positive how to correct my problem. I believe it might also have something to do with the properties of the box. I can enter "Dates" (my generic term for that range as defined by highlighting and labeling as such) under RowSource, though that is not looping the rows.
# Alex D
I am also attempting the path of the second post I received; i get a runtime error when I try to use:
Private Sub UserForm_Initialize()
For i = 2 To Sheets("Breakdown").UsedRange.Columns.Count
comboDate.AddItem (Cells(1, i))
comboDate.List(comboDate.ListCount - 1, 1) = i
Next
End Sub
Possibly moving where that data is defined would make this work? In general, I have a button in the sheet (aka one selects a cell and the userform pops up), so possibly the initialize isn't necessary?
Cyril 20140127 (1700 UTC)
Ok, let's go in reverse order. To your last question, "Is my end goal possible?", the answer is "sure." I don't quite follow your reasoning, but if you prefer to use Excel, so be it. I do think, though, that this going to be a painful way of recording PTO. What if, for example, I take a week off? Do I have to fill out this form once for each day?
To continue moving in reverse, your buttons need to do something. It's unclear from what you've posted if cmdCancel and cmdOK are subs that you've defined elsewhere so let's pretend they aren't. In your Cancel button you need to do one basic thing, close the form. That should be as simple as this, Unload Me.
Your OK button is the crucial piece of your macro. It's where you stitch together the values the user has entered. It's also where you do something with your option buttons. You don't actually assign values to the option buttons, you check their Value properties. So, when you users click OK the code that runs will have something in it like this:
If OptionButton1.Value = True Then
'Put 1 in the cell.
Else
'Put .5 in the cell.
End if
Note that there's no need to explicitly check OptionButton2, since you only have two choices.
Finally, the dates. It sounds like the dates are already in your spreadsheet, in some particular row. What you need to do here is loop through the cells in that row and pull the values into the list of the combo box. This should get you started. Put it the UserForm_Activate form event:
Dim i As Long
i = 1
Do While ThisWorkbook.ActiveSheet.Cells(DateRow, i).Value <> ""
Me.ComboBox1.AddItem (ThisWorkbook.ActiveSheet.Cells(DateRow, i).Value)
i = i + 1
Loop
Now we return to the OK button. You need to get the selection that was made in the date combo box. To do that you need to read the ListIndex property of the combo box and add one to it. (Adding 1 accounts for the fact that the list in the combo box starts 0, not 1.) The number that is the returned will be the column in which you insert your data.
The complete code for the OK button would be something like:
Dim Col As Long
Dim Row As Long
Dim PTOValue As Long
Col = DateComboBox.ListIndex + 1
Row = EmployeeNameComboBox.ListIndex + 1
If FullDayComboBox.Value = True Then
PTOValue = 1
Else
PTOValue = .5
End if
ThisWorkbook.ActiveSheet.Cells(DateRow, i).Value = PTOValue
Hopefully this will get you started.
Fills your criterion, and should be understandable. Assumes names start in cell(2,1) and Dates in cell(1,2). You might have to change some of the names of the elements depending on what you have. But I fully built something like you described and it works perfectly.
It does need some data validation to prevent errors, but you should be able to handle that.
'Ok button which sets the values
Private Sub CommandButton1_Click()
Columns("A:A").Select
If OptionButton1.Value = True Then
Cells(Get_Name_Row(comboName.Text), Get_Date_Column(comboDate.Text)).Value = 1
Else
Cells(Get_Name_Row(comboName.Text), Get_Date_Column(comboDate.Text)).Value = 0.5
End If
End Sub
'Cancel Button
Private Sub CommandButton2_Click()
Unload Me
End Sub
'This loads the dates into your comboBox, make sure to update its name
'I assume you use RowSource for your names, so those should be fine
Private Sub UserForm_Initialize()
For i = 2 To Sheets("Sheet1").UsedRange.Columns.Count
comboDate.AddItem (Cells(1, i))
comboDate.List(comboDate.ListCount - 1, 1) = i
Next
End Sub
'Gets what row the name is from
Public Function Get_Name_Row(SearchString As String) As Integer
Dim Rng As Range
If Trim(SearchString) <> "" Then
With Sheets("Sheet1").Range("A:A")
Set Rng = .Find(What:=SearchString, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
Get_Name_Row = CInt(Rng.Row)
End If
End With
End If
End Function
'Gets what column the date is from
Public Function Get_Date_Column(SearchString As String) As Integer
Dim Rng As Range
If Trim(SearchString) <> "" Then
With Sheets("Sheet1").Range("A1").EntireRow
Set Rng = .Find(What:=SearchString, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
Get_Date_Column = (Rng.Column)
End If
End With
End If
End Function