VBA: Array cell reference Mismatch error - vba

UPDATED 3/30
So I adjusted the code and it runs error free now but the issue is that it does not pull the correct data. X basically starts with cell(X,1) and goes on from there. How do I link X to the selected listbox options in the array?
OLD Message:
I have a userform that allows for multi-select of Countries and also Questions about that specific country. These are stored in arrCountries & arrQuestion respectively. This then feeds to my main sub which calls for a Web Query Import from the CIA World Factbook site. I keep however getting a mismatch error that I cannot seem to sort out how to get around:
If I had to guess it is because when I am filling the array from the listbox's it is just adding a string and not the cell reference that the string is located at (or I am completely wrong).
My worksheet has only 1 sheet when started called Countries and the Column A is the URL and Column B is the Country name. I have Defined Public arrCountry(), Public arrQuestion(), and Public X as variant.
Code here:
Userform Code when click okay:
'Handles when the user clicks okay
Private Sub cbOkay_Click()
'Me.Hide
'Capture ticker selection(s) from list box.
Dim cI As Long
Dim cX As Long
Dim qI As Long
Dim qX As Long
'Stores the Countries selected into an array
If lbCountries.ListIndex <> -1 Then
For cI = 0 To lbCountries.ListCount - 1
If lbCountries.Selected(cI) Then
ReDim Preserve arrCountry(cX)
arrCountry(cX) = lbCountries.List(cI)
cX = cX + 1
End If
Next cI
End If
If cX = 0 Then MsgBox "Please select at least one country to analyse."
'MsgBox Join(arrCountry, vbCrLf)
'Stores the Questions selected into an array
If lbQuestions.ListIndex <> -1 Then
For qI = 0 To lbQuestions.ListCount - 1
If lbQuestions.Selected(qI) Then
ReDim Preserve arrQuestion(qX)
arrQuestion(qX) = lbQuestions.List(qI)
qX = qX + 1
End If
Next qI
End If
If qX = 0 Then MsgBox "Please select at least one question to analyse."
'MsgBox Join(arrQuestion, vbCrLf)
'Unload the form
Unload Me
cancel = False
End Sub
The message boxes return the correctly selected Listbox items so I know they are being stored correctly.
The WebQuery Code I am getting the error on:
UPDATED CODE:
So I added a loop counter:
Sub webQueryimport(arrCountry())
Dim mystr As String
Dim X As Integer
Dim selected As Variant
For Each selected In arrCountry
X = X + 1
Worksheets("Countries").Select
Worksheets("Countries").Activate
mystr = Cells(X, 1)
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = selected
With ActiveSheet.QueryTables.Add(Connection:=mystr, Destination:=Range("$A$1"))
.WebSelectionType = xlEntirePage 'this tells VBA what to select and import
.WebFormatting = xlWebFormattingNone 'this turns off web formatting, otherwise text is various sizes
.Refresh BackgroundQuery:=False 'if commented out, doesn't add any data
End With
Next selected
End Sub
Again, now that loop works and will import but it always starts with the A1 no matter what is selected in the listbox and in arrCountries
Any thoughts/assistance would be great!

Got it:
Sub webQueryimport(arrCountry())
Dim mystr As String
Dim X As Integer
Dim rng As Range
Dim selected As Variant
Set rng = Range("B1")
For Each selected In arrCountry()
For X = 1 To 5 'rng.Offset(0, 0).End(xlDown).Rows.count
Worksheets("Countries").Select
Worksheets("Countries").Activate
If Cells(X, 2).Value = selected Then
mystr = Cells(X, 1).Value
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = selected
With ActiveSheet.QueryTables.Add(Connection:=mystr, Destination:=Range("$A$1"))
.WebSelectionType = xlEntirePage 'this tells VBA what to select and import
.WebFormatting = xlWebFormattingNone 'this turns off web formatting, otherwise text is various sizes
.Refresh BackgroundQuery:=False 'if commented out, doesn't add any data
End With
End If
Next X
Next selected
End Sub
I needed to add in a counter and the IF statement to check to see if the value in the array matched the cell value in the sheet and then return the appropriate cell for the import.

Related

Macro fires 50% of the time when changing slicer item

I have a particular problem and couldn't find any solution anywhere on the internet.
So I have a pivot table which is connected to 6 slicers and also a chart which data range is dependent on pivot table values.
I've made a macro which updates chart scales everytime a value in any of the worksheet cells is changed. Here is the macro:
Public Sub worksheet_Change(ByVal Target2 As Range)
If ActiveSheet.Name = "Dashboard" Then
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DataEntryMode = xlOff
'Chart_axis Macro
Sheets("Dashboard").ChartObjects("Chart 9").Activate
If ActiveSheet.Range("B19") = "excluding CE" Then
ActiveChart.Axes(xlValue).MinimumScale = Range("E3").Value
ActiveChart.Axes(xlValue).MaximumScale = Range("E4").Value
Else
ActiveChart.Axes(xlValue).MinimumScale = Range("A3").Value
ActiveChart.Axes(xlValue).MaximumScale = Range("A4").Value
End If
ActiveChart.Refresh
ActiveSheet.Range("B18").Select
Application.EnableEvents = True
Application.ScreenUpdating = True
End If
End Sub
In order to work as intended i also had to made a function which reads the active elements of a slicer:
Public Function GetSelectedSlicerItems(SlicerName As String) As String
Application.Volatile
Set coll = New Collection
Dim cache As Excel.SlicerCache
Dim i As Integer
Set cache = ActiveWorkbook.SlicerCaches(SlicerName)
Dim sItem As Excel.SlicerItem
Dim result As String
For Each sItem In cache.SlicerItems
If sItem.Selected And sItem.HasData Then
'Debug.Print sItem.Name
'Debug.Print sItem.HasData
'GetSelectedSlicerItems = (sItem.Name)
coll.Add sItem.Name
End If
Next sItem
For i = 1 To coll.Count
'Debug.Print coll(i)
result = result & coll(i) & ", "
Next i
result = Left(result, Len(result) - 2)
GetSelectedSlicerItems = result
End Function
My problem is that while the value of the function always updates when the slicer item is changed, the macro only does it randomly about 50% of the time.
Screenshot of my report:
The formulas containing the selected slicer items function are on the top right.
So do you have any idea how to make it work 100% of the time?
Thanks in advance,
Alan
Edit: i forgot to add that it's only the issue if only one slicer is highlited. When i select multiple slicers (with ctrl+click) it always works.

Array insertion of Duplicated and not duplicated data to different column in VBA

Good day! in my worksheet i have (1) textbox as TextBox1 and 1 button for submit button. I have here sample code that gives splitted text as an output. I just want that if there's duplicated word in textbox1 and the user enters the submit button it will saves to worksheet(DatabaseStorage) and categorize the output from No Duplicated Word and With duplicated Word. Because this two different fields will be needed for some function of the system.
Private Sub CommandButton1_Click()
Call SplitText
End Sub
Sub SplitText()
Dim WArray As Variant
Dim TextString As String
TextString = TextBox1
WArray = Split(TextBox1, " ")
If (TextString = "") Then
MsgBox ("Error: Pls Enter your data")
Else
With Sheets("DatabaseStorage")
.Cells(.Rows.Count, 1).End(xlUp).Offset(1, 0).Resize(UBound(WArray) + IIf(LBound(WArray) = 0, 1, 0)) = Application.Transpose(WArray)
End With
MsgBox ("Successfully inserted")
End If
End Sub
This should accomplish what you need. I loop through the array to check if the given value exists in the "No Duplicates" column. If not, don't print it there.
Any time I encounter a situation where I need to check a single value against a list (ex. check for duplicates, GT/LT, etc.), I consider looping.
Sub SplitText()
Dim WArray As Variant
Dim TextString As String
Dim col_no_dup As Long
Dim col_dup As Long
Dim counter As Integer
Dim sht_database As Worksheet
With ThisWorkbook
Set sht_database = .Sheets("DatabaseStorage")
TextString = LCase(.Sheets("Sheet1").Shapes("Textbox1").DrawingObject.Text)
End With
WArray = Split(TextString, " ") 'load array
If (TextString = "") Then
MsgBox ("Error: Pls Enter your data")
End
Else: End If
'set column locations for duplicates/no duplicates
col_no_dup = 1
col_dup = 2
With sht_database
.Range("A2:B10000").ClearContents 'clear existing data. Change this as needed
'Print whole array into duplicates column
.Cells(Cells.Rows.Count, col_dup).End(xlUp).Offset(1, 0).Resize(UBound(WArray) + IIf(LBound(WArray) = 0, 1, 0)) = Application.Transpose(WArray)
'Loop through array
For i = LBound(WArray) To UBound(WArray)
counter = 0
lrow_no_dup = .Cells(Cells.Rows.Count, col_no_dup).End(xlUp).Row
For n = 1 To lrow_no_dup 'loop through and check each existing value in the no dup column
If .Cells(n, col_no_dup).Value = WArray(i) Then
counter = counter + 1 'account for each occurence
Else: End If
Next n
If counter = 0 Then 'counter = 0 implies the value doesn't exist in the "No Duplicates" column
.Cells(lrow_no_dup + 1, col_no_dup).Value = WArray(i)
Else: End If
Next i
End With
MsgBox ("Successfully inserted")
End Sub

Looping through Excel Cells and writing them to Word

I am using a Macro in Excel to loop through cells and write the data into a Template in Word. Everything worked completely fine until I wanted to add more cells to grab data from. Everything still works fine except once the variable I have name "j" gets to the value of 25, I get an error saying "Run-time error '5941': The requested member of the collection does not exist."
I've played around with using different rows and columns and every combination works. It is only when the "j" reaches 25 does the error occur. It is failing when it reaches the wrd.ActiveDocument.Tables(1).Rows(j)... line.
Sub Label_ExcelToWord_Single()
'Variable that stores file path for
'word template
Dim strpath As String
strpath = Cells(28, 8)
'opens Microsoft Word to edit template
Call OpenWord
Set wrd = GetObject(, "Word.Application")
wrd.Visible = True
wrd.Activate
wrd.ActiveDocument.Close savechanges:=False
wrd.Documents.Open strpath
'Variables used for loop data manipulation
Dim k As Integer
Dim j As Integer
k = 1
j = 1
'Primary loop responsible for exporting Excel
'data to word template
For Col = 1 To 3
For Row = 3 To 32
wrd.ActiveDocument.Tables(1).Rows(j).Cells(((Row - 3) Mod 7) + k).Range.Text = Cells(Row, Col) & vbCrLf & Cells(Row, Col)
If k = 7 Then
k = 0
j = j + 2
End If
If Col = 3 Then
If Row = 32 Then
'When we reach the last cell containing data exit routine
Exit Sub
End If
End If
k = k + 1
Next
Next
End Sub
I think it's a lot easier to use DocVariables in Word and push your data from Excel cells into the DocVariables. The end game is about the same, but I think the code is a lot easier to setup and maintain.
Sub PushToWord()
Dim objWord As New Word.Application
Dim doc As Word.Document
Dim bkmk As Word.Bookmark
sWdFileName = Application.GetOpenFilename(, , , , False)
Set doc = objWord.Documents.Open(sWdFileName)
'On Error Resume Next
objWord.ActiveDocument.variables("FirstName").Value = Range("FirstName").Value
objWord.ActiveDocument.variables("LastName").Value = Range("LastName").Value
objWord.ActiveDocument.variables("AnotherVariable").Value = Range("AnotherVariable").Value
objWord.ActiveDocument.Fields.Update
'On Error Resume Next
objWord.Visible = True
End Sub
Set a reference ot the MS Word Object Library.
Looks like the table might not have enough rows. If so, a brute-force way is to add rows as you need them:
...
For Col = 1 To 3
For Row = 3 To 32
' vvv new lines vvv
Do While wrd.ActiveDocument.Tables(1).Rows.Count < j
wrd.ActiveDocument.Tables(1).Rows.Add
Loop
' ^^^ new lines ^^^
...
I also recommend renaming j, k, Row, and Col to more descriptive names. You have Excel row/column indices and Word-table row/column indices, and it's easy to get them confused unless the names are clear.
(Note: Yes, the above code is slow, clunky, unoptimized, yadda yadda. Hopefully it will help the OP. :) )

How to display Values from a multiselect listbox

I have a form in Excel macro. This form will capture the values inserted in textboxes, listbox and store in Sheet2.
There are 2 buttons in the form applet named "Next" and "Previous". These button will be used for navigating between the saved records. I am able to navigate between records and the values display fine in textboxes. However, I am not sure how can I display the Values from listboxes. My list box is a multiselect list box.
I have provided snippet of my code on how the records are saved in sheet2 and how the navigation happens when clicked on Next button.
Private Sub Save_Click()
Dim ctl As Control
Dim S As String
Dim i As Integer
RowCount = Worksheets("Sheet2").Range("A1").CurrentRegion.Rows.Count
With Worksheets("Sheet2").Range("A1")
.Offset(RowCount, 0).Value = Me.Name1.Value ' capture value from list box
'below code is for capturing value from multiselect listbox
With AOI
For i = 0 To .ListCount - 1
If .Selected(i) = True Then S = S & ", " & .List(i)
Next i
Range("A1").Offset(RowCount, 10).Value = S
End With
End Sub
Below code is for navigating between saved records..
Private Sub Next1_Click()
strCurrentSetofRows = Worksheets("Sheet2").Range("A1").CurrentRegion.Rows.Count
i = i + 1: j = 0
If i > (strCurrentSetofRows - 1) Then
MsgBox "No More Records"
Exit Sub
End If
Set sRange = Worksheets("Sheet2").Range("A1")
Name1.Text = sRange.Offset(i, j).Value: j = j + 1
End Sub
Any thoughts on how can I display saved values of AOI (my field).
Since you are storing the values using , as a separator, you can use the same to split the values and upload it to the ListBox. BTW, I hope you are generating the ListBox with the complete list in the UserForm's Initialize event?
Here is a very basic example. Please amend it to suit your needs.
Let's say Cell A1 has Blah1,Blah2,Blah6. Then try this code
Option Explicit
Dim i As Long, j As Long
Private Sub UserForm_Initialize()
ListBox1.MultiSelect = fmMultiSelectMulti
For i = 1 To 10
ListBox1.AddItem "Blah" & i
Next
End Sub
Private Sub CommandButton1_Click()
Dim ArValues As Variant
Dim sValue As String
Dim multivalues As Boolean
If InStr(1, Range("A1").Value, ",") Then
ArValues = Split(Range("A1").Value, ",")
multivalues = True
Else
sValue = Range("A1").Value
multivalues = False
End If
If multivalues = True Then
For i = 0 To UBound(ArValues)
For j = 0 To ListBox1.ListCount - 1
If ListBox1.List(j) = ArValues(i) Then
ListBox1.Selected(j) = True
Exit For
End If
Next j
Next i
Else
For j = 0 To ListBox1.ListCount - 1
If ListBox1.List(j) = sValue Then
ListBox1.Selected(j) = True
Exit For
End If
Next j
End If
End Sub
Screenshot

Excel VBA crashes after subroutine finishes

This script is to reset a template, by copying a hidden worksheet template and deleting the existing sheet (after repopulating some reference data). I have tested it and it runs fine in debugging mode.
Option Explicit
Sub reset_PrintLayout_byCopy()
'the script replace the used printlayout with a copy from the hidden master.
Dim MeetingData() As String
Dim i As Integer
Dim j As Integer
Dim currentSheet As String
Dim datacolumns() As String
Dim userConfirm As String
ReDim Preserve MeetingData(3, 2)
ReDim Preserve datacolumns(2)
'warning about deleting data
userConfirm = MsgBox(Prompt:="Resetting the template will erase all data on the " _
& "PrintLayout Template. Choose ""Cancel"", if you wish to save the file first", _
Buttons:=vbOKCancel, Title:="Data to be erased!")
If (userConfirm = vbCancel) Then
Exit Sub
End If
'set parameters
datacolumns(0) = "D1"
datacolumns(1) = "I1"
'stop screen updating and displaying warnings
Application.ScreenUpdating = False
Application.DisplayAlerts = False
'set active sheet
currentSheet = ActiveSheet.Name
'capture meeting data already filled out
For j = 0 To UBound(datacolumns) - 1
For i = 1 To 3
If Worksheets(currentSheet).Cells(i, Range(datacolumns(j)).Column).Value <> "" Then
MeetingData(i - 1, j) = Worksheets(currentSheet).Cells(i, Range(datacolumns(j)).Column).Value
End If
Next i
Next j
'make hidden template visible
Worksheets("hiddenPrintLayoutTemplate").Visible = True
'Rename current Sheet
Sheets(currentSheet).Name = "used_Print_Layout"
''add a new sheet
' ActiveWorkbook.Worksheets.Add(before:=Sheets("used_Print_Layout")).Name = "PrintLayout Template"
'copy hiddentemplate before current sheet
Worksheets("hiddenPrintLayoutTemplate").Copy before:=Sheets("used_Print_Layout")
ActiveSheet.Name = currentSheet
'set rowheight for title rows
Range("A12").EntireRow.RowHeight = 24
Range("A18").EntireRow.RowHeight = 24
'delete current used printlayout
Worksheets("used_Print_Layout").Delete
'refilled meeting data
For j = 0 To UBound(datacolumns) - 1
For i = 1 To 3
If MeetingData(i - 1, j) <> "" Then
Worksheets(currentSheet).Cells(i, Range(datacolumns(j)).Column).Value = MeetingData(i - 1, j)
End If
Next i
Next j
'hide PrintLayout template
'Worksheets("hiddenPrintLayoutTemplate").Visible = xlSheetVeryHidden
'Sheets("PrintLayout Template").Select
'activate screenupdating and display warnings
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
When run it in macro mode on button, it runs, but excel crashes, when it is done. I cannot find what the issue is. Any ideas?
I am not sure if by debugging you mean stepping through line by line, but you could try inserting stop statements at key points in the code. So for example, you could put a stop statement in the following part:
'capture meeting data already filled out
For j = 0 To UBound(datacolumns) - 1
For i = 1 To 3
If Worksheets(currentSheet).Cells(i, Range(datacolumns(j)).Column).Value <> "" Then
MeetingData(i - 1, j) = Worksheets(currentSheet).Cells(i,Range(datacolumns(j)).Column).Value
End If
Next i
Next j
stop
'make hidden template visible
Worksheets("hiddenPrintLayoutTemplate").Visible = True
You could see if the code runs fine up until that point (i.e. run it without debugging). If it does, remove the stop statement and place it further down the code. Repeat this until you find the statements which cause your crash - perhaps the reason would appear then.
In general, if you get an odd crash in Excel VBA, try switching the Windows default printer to Microsoft XPS Document Writer. Seems odd, but that has worked for me on problems where I've wasted many hours only to find this is the culprit.