VBA Textbox value loop vlookup for number of times value is found - vba

I am creating a table in my spreadsheet that contains categories, questions and answers for a quiz.
The user is presented with a form, allowing them to navigate around the workbook easily, this also includes a textbox option, allowing them to search for a phrase if they are unsure what category the question/answer may fall into.
I have generated a vlook up to pull from the table of categories/questions and answers to the user on a different worksheet.
I have also generated a count, so I am able to identify how many times this work appears across the quiz table.
My problem is I am struggling to develop a loop so that if the key phrase is found 6 times for example, i want 6 questions and answers to be listed to the user. Currently it is only pulling the final time it is found.
My current code includes the following:
Private Sub CommandButton1_Click()
If Len(search_text) = 0 Then
MsgBox "Please enter a key word to search for!", vbCritical
End If
Dim wordCount As Integer
wordCount = Application.WorksheetFunction.CountIf(Sheet1.Range("A2:c600"), "*" & search_text.Value & "*")
'Else: wordCount = WorksheetFunction.CountIf(Sheet1.Range("A2:c600"), search_text.Value)
If wordCount = 0 Then
MsgBox "No match found"
Else
Sheet2.Range("a7").Value = WorksheetFunction.VLookup("*" & search_text.Value & "*", Sheet1.Range("A2:c600"), 3, False)
Sheet2.Range("b7") = wordCount
End If
End Sub
Any advice on implementing a loop and to allow the question/answer to be printed one after another would be very much appreciated.
I have read many other question pages about this and none seem to match what I am trying to do.
Many thanks in advance

I use a combination of Find and FindNext to search through a range of cells for the term entered in the search_text input field. I added comments to my code to better help you understand what exactly is going on.
I don't know exactly what you need to do with the results when you find them, for now I just display a message box showing the match. We can work on what to actually do with the results if you want to clarify in the comments what exactly you want.
This code assumes you have a worksheet named Results
Private Sub CommandButton1_Click()
Dim rngResult As Range
Dim strFirstAddress As String
Dim i As Long
If Len(search_text.Text) = 0 Then
MsgBox "Please enter a key word to search for!", _
vbCritical
'Stop code exeuction if no search
'term is entered
Exit Sub
End If
'Clear the previous results range
Sheets("Results").Range("A2:C600").ClearContents
'Set i to row 2 of the results worksheet
i = 2
'Look in range A2:C600 of Sheet1
With Sheet1.Range("A2:C600")
'Perform the initial find
Set rngResult = .Find(What:=search_text.Text, LookAt:=xlPart)
'Check to ensure that the term is found
If Not rngResult Is Nothing Then
'Grab the cell address of the first match
'This will help to avoid an infinite loop
strFirstAddress = rngResult.Address
'Continue Searching
Do
'Display the output to you
'MsgBox "Matched '" & search_text.Text & "' to " & rngResult.Value & " in cell " & rngResult.Address
'Put the result on the results page
Sheets("Results").Range("A" & i & ":C" & i).Value = Range("A" & rngResult.Row & ":C" & rngResult.Row).Value
i = i + 1
'Move on to the next result
Set rngResult = .FindNext(rngResult)
'Break out of the loop when we return to the starting point of the search
Loop While Not rngResult Is Nothing And rngResult.Address <> strFirstAddress
End If
End With
'Clean up variables
Set rngResult = Nothing
End Sub

Related

why does my VBA code that works in module not work as expected when assigned to a worksheet and a button

I have a workbook that is essentially an automated test, marking and feedback tool for end of topic tests for students. On the '701Test' sheetThey input their teaching group via a drop down list and the select their from subsequent list. They answer the multiple choice questions and press a button when finished. The button takes them to a 'results' page which gives their marks for each question, give feedback for incorrect answers and gives a total score. They then hit the finish button which generates a PDF copy of the mark sheet in their my documents folder and then emails a copy to themselves and the Schools email account. At this point I also wanted to post the final score to the students record on a central registry using a loop through the student list to find the name and offset to post the Score value from the 'Results' page and finally return to the test page. This last bit I wrote the code for in a module and it executes perfectly, but when added to the main code and run from the button the loop part fails to execute but the return to the test page does work, but no error is recorded for the loop failure.
Here is the 'Results' page code in full the 'With Central reg' bit at the bottom is the problem, any help is greatly appreciated.
Private Sub CommandButton1_Click()
Dim IsCreated As Boolean
Dim PdfFile As String, Title As String
Dim OutlApp As Object
Dim cell As Range
Dim Students As Range
Title = Range("D1").Value
sname = Range("B2").Value
PdfFile = CreateObject("WScript.Shell").SpecialFolders("MyDocuments") & "\" & sname & Title & ".pdf"
With ActiveSheet
.ExportAsFixedFormat Type:=xlTypePDF, Filename:=PdfFile, Quality:=xlQualityStandard, IncludeDocProperties:=True, IgnorePrintAreas:=False, OpenAfterPublish:=False
End With
On Error Resume Next
Set OutlApp = GetObject(, "Outlook.Application")
If Err Then
Set OutlApp = CreateObject("Outlook.Application")
IsCreated = True
End If
OutlApp.Visible = True
On Error GoTo 0
With OutlApp.CreateItem(0)
.Subject = Title
.to = Range("B2").Value ' <-- Put email of the recipient here"
.CC = "" ' <-- Put email of 'copy to' recipient here
.Body = "Hi," & vbLf & vbLf _
& "Yr 7 701 EOT test attached in PDF format." & vbLf & vbLf _
& "Regards," & vbLf _
& "KDS ICT Dept" & vbLf & vbLf
.Attachments.Add PdfFile
Application.Visible = True
.Display
End With
If IsCreated Then OutlApp.Quit
Set OutlApp = Nothing
With CentralReg
For Each cell In Range("A2:A250")
If cell = Range("Results!B2").Value Then
cell.Offset(0, 4).Activate
ActiveCell.Value = Range("Results!B27").Value
End If
Next
End With
End Sub
I believe you are trying to refer to CentralReg which is a worksheet, which means you should qualify it as such.
Also, you should not dim variables that are similar to defined objects/properties in VBE. Try MyCell instead of cell (good practice, not required).
I am assuming you want to see if the value on sheet CentralReg in Column A is equal to sheet Result B2. If this condition is met, your MyCell will take on the value equal sheet Result B27
Dim MyCell As Range
Dim Result, NewValue as Variant
Result = ThisWorkbook.Sheets("Result").Range("B2")
NewValue = ThisWorkbook.Sheets("Result").Range("B27")
With ThisWorkbook.Sheets("CentralReg")
For Each MyCell In .Range("A2:A250")
If MyCell = Result Then MyCell.Offset(, 4) = NewValue
Next MyCell
End With
That with statement is useless as nothing actually uses it within the construct.
Delete with CentralReg and End with and it will work.
alternatively if CentralReg IS something like a sheet then you need to precede your code with a . so this: Range("A2:A250") becomes this: .Range("A2:A250") and so on, the . tells the code that it is related to whatever your with construct surrounds

How to check if string appears in worksheet *twice* Excel VBA?

I'm trying to check if a certain string appears on a given sheet twice. So far, I'm only able to check if the string appears once:
For Each curr In wb.Worksheets(1).UsedRange
If InStr(1, curr.Value, searchString) > 0 Then
MsgBox ("searchString appears once")
End If
Next
How do I check the UsedRange to see if the value appears twice? This needs to be a macro (so far I've found formulas that do this).
If WorksheetFunction.CountIf(Worksheets(1).UsedRange, "*" & searchString & "*") > 1 Then
MsgBox searchString & " appears more than once"
End If
Set a flag when you find the first match, then check to see if the flag is set:
Dim first As Boolean
For Each curr In wb.Worksheets(1).UsedRange
If InStr(1, curr.Value, searchString) > 0 Then
If first Then MsgBox ("searchString appears twice")
first = True
End If
Next

VBA runtime error 13 using Msgbox

I'm very new to VBA and only have a basic level of knowledge.
I have been trying to create a macro to cross-reference data on one sheet against multiple other sheets within the same work book. If a record is found I would like a msgbox to appear to alert the user of the location of the data.
After many hours searching the internet and piecing together bits of code this is what I have
Sub search()
Dim ws As Worksheet, found As Range
Dim TextToFind(1 To 20) As String
Dim iText As Long
TextToFind(1) = "Jade Smith"
TextToFind(2) = "Bob Collins"
TextToFind(3) = "Jemima Smythe"
For Each ws In ThisWorkbook.Worksheets
With ws
If .Name <> "Blacklisted Candidates" Then 'Do not search blacklist candidates!
iText = 1
Do While iText <= UBound(TextToFind)
If TextToFind(iText) <> "" Then 'Do not search blank strings!
Set found = .UsedRange.Find(what:=TextToFind(iText), LookIn:=xlformulas, LookAt:=xlPart, MatchCase:=False)
If Not found Is Nothing Then
MsgBox "Proxy Candidate Found at " & found.Address
Else
MsgBox "No Proxy Candidates Found ", vbOKOnly, "Success!"
End If
iText = iText + 1
End If
Loop
End If
End With
Next ws
End Sub
This code however doesn't find the values from other sheets.
when testing this I just get the msgbox when no data has been found even though there is test data there.
I have a workbook of approx 9 sheets (ever growing) and I want to search the first 9 columns of each work book for the specified data which as you can see I have manually input into the macro but when running the macro I get no results returned even though there is data to find.
You are trying to use the binary operator And on two strings. You probably meant to use & instead to concatenate strings.
Documentation :
And
&
(The docs are for VB.Net, but they work the same in both languages)
So to fix it, replace
MsgBox ("Proxy Candidate Found at " And rngX.Address)
By
MsgBox ("Proxy Candidate Found at " & rngX.Address)
edited to account for searching in cell whose content derives from a formula
to both summarize all what has been already pointed out in comments and litelite answer and add some 0.02 cents, here a working code
Option Explicit
Sub search()
Dim ws As Worksheet, found As Range
Dim TextToFind(1 To 20) As String
Dim iText As Long
TextToFind(1) = "xxxx"
TextToFind(2) = "xxxx"
TextToFind(3) = "xxxxx"
For Each ws In ThisWorkbook.Worksheets
With ws
If .name <> "Blacklisted Candidates" Then 'Do not search blacklist candidates!
iText = 1
Do While iText <= UBound(TextToFind)
If TextToFind(iText) <> "" Then 'Do not search blank strings!
Set found = .UsedRange.Find(what:=TextToFind(iText), LookIn:=xlFormulas, LookAt:=xlPart, MatchCase:=False)
If Not found Is Nothing Then
MsgBox "Proxy Candidate Found at " & found.Address
Else
MsgBox "No Proxy Candidates Found ", vbOKOnly, "Success!"
End If
iText = iText + 1
End If
Loop
End If
End With
Next ws
End Sub

excel checkspelling single cell

I'm struggling a bit with CheckSpelling in Excel. I have a merged cell that I want to check, but only this cell. Here's what I'm doing.
ActiveSheet.Unprotect strSheetPassword
Application.DisplayAlerts = False
Set ma = Range("B21").MergeArea
ma.MergeCells = False
Union(Range("B1"), ma(1, 1)).CheckSpelling
ma.MergeCells = True
Application.DisplayAlerts = True
ActiveSheet.Protect strSheetPassword
It's checking the cell I want, but it's also checking the rest of the document. In reading other posts, I got the impression that checking a single cell causes CheckSpelling to check the entire document. This is why I put in the Union with the Range("B1") - B1 contains header text that doesn't have any misspellings and is normally locked, so that users can't change it. But, it is still checking the rest of the sheet! I've tried quite a few variations on this, but it still keeps checking the rest of the sheet.
CONCLUSION
I had been under the impression that it was possible to invoke the CheckSpelling form and have it only check certain cells. Apparently, this isn't true. Instead of building my own form, I should be able to get away with checking the whole sheet each time, although I really don't like that. Thanks for all the feedback!
For a single merged cell:
Sub spell_me()
Dim b As Boolean
b = Application.CheckSpelling(Word:=ActiveCell.Text)
MsgBox b & vbCrLf & ActiveCell.Address & vbCrLf & ActiveCell.Text
End Sub
EDIT#1:
To find the miscreant word, you could Split() the text into individual words and check each word.
If it is enough if the wrong part gets highlighted you can use this:
Sub SpellCheck()
Dim response As Boolean
Dim words As Variant
Dim wordCount As Long
Dim startAt As Long
words = Split(ActiveCell.Text, " ")
'set all of the text to automatic color
ActiveCell.Font.ColorIndex = xlAutomatic
For wordCount = LBound(words) To UBound(words)
response = Application.CheckSpelling(word:=words(wordCount))
If Not response Then
'find out where it is in the text and color the font red
startAt = InStr(ActiveCell.Text & " ", words(wordCount) & " ")
ActiveCell.Characters(Start:=startAt, Length:=Len(words(wordCount))).Font.Color = vbRed
End If
Next
End Sub

Excel VBA Macro - Looping through a column of a filtered table

I have a spreadsheet with a whole bunch of data (A directory of weather stations) which calculates the closest weather stations to a user entered Latitude and Longitude. This worksheet achieves this by calculating distance from the entered point, ranking those distances using SMALL() and then an excel TABLE/List with formulas perform Index(Match()) type calculations using Rankings (1 is closest, 2 is 2nd closest etc).
The worksheet whilst slow, works fairly well - and the excel Tables allow for advanced sorting of the weather station directory by various criteria (Such as length of record in years etc).
I have a VBA Macro that I was writing which used to work, but stopped working when I tried to fix it (awesome).
The purpose of the VBA Macro is to write a Google Earth KML file with the lat/long/weather station name and then to launch that file into google earth so the user can visualise the proximate stations around a set site location (the one previously entered by the user).
Unfortunately the original method I used couldn't handle the Filtered Results of the List, such that if the user filtered the results (Such that the first 4 weather stations were filtered out as an example) the macro would still write the first four weather stations that were not Visible/Were Filtered.
The problem for me is made more difficult as I wish to have only one macro for four worksheets with filter-able tables - for different data types.
At this stage the data the macro needs are stored in the Tables in identically named Table Columns: {"STATION","LONGITUDE","LATITUDE"} in different worksheets. The majority of the KML strings required to write to the KML file are stored in another hidden worksheet "KML".
The macro is launched via a button on each of these pages.
I understand that there could be a solution using ".SpecialCells(xlCellTypeVisible)" - and I've tried extensively to get it to work with my Tables - but have had no luck so far - probably due to my lack of formal training.
Any help appreciated, be it a solution or a suggestion! Apologies for my bad code, the problem loop & broken code area is about halfway down - after 'Find all table on active sheet:
Sub KML_writer()
Dim FileName As String
Dim StrA As String
Dim NumberOfKMLs
Dim MsgBoxResponse
Dim MsgBoxTitle
Dim MsgBoxPrompt
Dim WhileCounter
Dim oSh As Worksheet
Set oSh = ActiveSheet
'Prompt the Number of Stations to Write to the KML File
NumberOfKMLs = InputBox(Prompt:="Please Enter the number of Weather Stations to generate within the Google Earth KML file", _
Title:="Number of Weather Stations", Default:="10")
'Prompt a File Name
FileName = InputBox(Prompt:="Please Enter a name for your KML File.", _
Title:="Lat Long to KML Converter", Default:="ENTER FILE NAME")
'Will clean this up to not require Write to Cell and Write to KML duplication later
Sheets("kml").Range("B3").Value = FileName
Sheets("mrg").Range("C5").Value = "Exported from EXCEL by AJK's MRG Function"
saveDir = "H:\" 'Local Drive available for all users of macro
targetfile = saveDir & FileName & ".KML"
'Write Site Location to KML STRING - user entered values from SITE LOCATION worksheet
StrA = Sheets("kml").Range("B1").Value & Sheets("kml").Range("B2").Value & "SITE LOCATION" & Sheets("kml").Range("B4").Value & Sheets("INPUT COORDINATES").Range("E5").Value & Sheets("kml").Range("B6").Value & Sheets("INPUT COORDINATES").Range("E4").Value & Sheets("kml").Range("B8").Value
'Find all tables on active sheet
Dim oLo As ListObject
For Each oLo In oSh.ListObjects
'
Dim lo As Excel.ListObject
Dim lr As Excel.ListRow
Set lo = oSh.ListObjects(oLo.Name)
Dim cl As Range, rng As Range
Set rng = Range(lo.ListRows(1)) 'this is where it breaks currently
For Each cl In rng2 '.SpecialCells(xlCellTypeVisible)
'Stop looping when NumberofKMLs is written to KML
WhileCounter = 0
Do Until WhileCounter > (NumberOfKMLs - 1)
WhileCounter = WhileCounter + 1
Dim St
Dim La
Dim Lon
'Store the lr.Range'th station data to write to the KML
St = Intersect(lr.Range, lo.ListColumns("STATION").Range).Value
La = Intersect(lr.Range, lo.ListColumns("LATITUDE").Range).Value
Lon = Intersect(lr.Range, lo.ListColumns("LONGITUDE").Range).Value
'Write St La Long & KML Strings for Chosen Stations
StrA = StrA & Sheets("kml").Range("B2").Value & St & Sheets("kml").Range("B4").Value & Lon & Sheets("kml").Range("B6").Value & La & Sheets("kml").Range("B8").Value
Loop
Next
Next
'Write end of KML strings to KML File
StrA = StrA & Sheets("kml").Range("B9").Value
'Open, write, close KML file
Open targetfile For Output As #1
Print #1, StrA
Close #1
'Message Box for prompting the launch of the KML file
MsgBoxTitle = ("Launch KML?")
MsgBoxPrompt = "Would you like to launch the KML File saved at " & targetfile & "?" & vbCrLf & vbCrLf & "Selecting 'No' will not prevent the file from being written."
MsgBoxResponse = MsgBox(MsgBoxPrompt, vbYesNo, MsgBoxTitle)
If MsgBoxResponse = 6 Then ThisWorkbook.FollowHyperlink targetfile
End Sub
Here is an example of iteration over a filtered table. This uses a ListObject table which are a little easier to work with than just a range of autofiltered cells arranged like a table, but the same general idea can be used (except you can't call on the DataBodyRange of a non-ListObject table).
Create a table:
Apply some filter(s) to it:
Notice that several rows have been hidden, and the visible rows are not necessarily contiguous, so we need to use the .Areas of the table's DataBodyRange which are visible.
As you've already surmised, you can use the .SpecialCells(xlCellTypeVisible) to do this.
Here's an example:
Sub TestFilteredTable()
Dim tbl As ListObject
Dim rngTable As Range
Dim rngArea As Range
Dim rngRow As Range
Set tbl = ActiveSheet.ListObjects(1)
Set rngTable = tbl.DataBodyRange.SpecialCells(xlCellTypeVisible)
' Here is the address of the table, filtered:
Debug.Print "Filtered table: " & rngTable.Address
'# Here is how you can iterate over all
' the areas in this filtered table:
For Each rngArea In rngTable.Areas
Debug.Print " Area: " & rngArea.Address
'# You will then have to iterate over the
' rows in every respective area
For Each rngRow In rngArea.Rows
Debug.Print " Row: " & rngRow.Address
Next
Next
End Sub
Sample output:
Filtered table: $A$2:$G$2,$A$4:$G$4,$A$6:$G$6,$A$9:$G$10
Area: $A$2:$G$2
Row: $A$2:$G$2
Area: $A$4:$G$4
Row: $A$4:$G$4
Area: $A$6:$G$6
Row: $A$6:$G$6
Area: $A$9:$G$10
Row: $A$9:$G$9
Row: $A$10:$G$10
Try and adapt this method to your problem, and if you have a specific error/issue with implementing it, let me know.
Just remember to update your original question to indicate a more specific problem :)
I had to find a record in a filtered data and change one value
Sample data
I wanted to change sales personcode to customer C00005.
First i filtered and found customer to modify.
codcliente = "C00005"
enter 'make sure that this customer exist in the checked range
Set test = CheckRng.Find(What:=codcliente, LookIn:=xlValues, LookAt:=xlWhole)
If test Is Nothing Then
MsgBox ("Does not exist customer """ & codcliente & """ !")
DataSheet.AutoFilterMode = False
Else 'Customer Exists
With DataRng 'filter the customer
.AutoFilter Field:=1, Criteria1:=codcliente
End With
Set customer = DataRng.SpecialCells(xlCellTypeVisible) ´Get customer data. It is visible
customer.Cells(1, 6).Value = "NN" 'navigate to 6th column and change code
End If
enter image description here