VBA InputBox Issue

Anonymous
2021-03-05T18:47:39+00:00

I have a simple macro. To copy values from one workbook to another in this case ML to MCR based on the user input number.

Number format can be e.g M5888-9087, M1990A 600111512, 453564034421 822349224.

Macro works with numbers like M5888-9087 but if I enter M1990A 600111512 or 453564034421 822349224 it copies all the rows instead of filtering M1990A 600111512 or 453564034421 822349224 and copying those selected rows.

Space in between is the culprit. How to overcome this?

Does changing the filter helps? I see other filters in object library.

Sub MCR()

Dim myInp As Variant

myInp = VBA.Interaction.InputBox(Prompt:="Enter the number", Title:="MCR Macro")

Windows("ML.xlsx").Activate

Worksheets("Full-View").Select

Worksheets("Full-View").ListObjects("Table1").Range.AutoFilter Field:=1, Criteria1:=myInp

Range("Table1[[#Headers],[Serial]]").Select

ActiveCell.Offset(1, 7).Range("Table1[[#Headers],[Serial]]").Select

Range(Selection, Selection.End(xlDown)).Select

Selection.Copy

Windows("MCR Macro.xlsm").Activate

Range("A4").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _

:=False, Transpose:=False

End Sub

Microsoft 365 and Office | Excel | For home | Windows

Locked Question. This question was migrated from the Microsoft Support Community. You can vote on whether it's helpful, but you can't add comments or replies or follow the question.

0 comments No comments

99 answers

Sort by: Oldest
  1. OssieMac 48,006 Reputation points Volunteer Moderator
    2021-03-09T04:16:57+00:00

    @ExcelFunTension,

    Hope that I have covered all of you questions. See the edited version of the code at bottom of this post.

    Q1) I have a question on strPrompt. At the start we assigned strPrompt to a text.

    During validation again we assigned strPrompt to a text.

    How does second strPrompt invoke InputBox? Just because it was part of Inputbox earlier?

    In COUNTA code, if I enter a invalid number or type a single number it throws an error 1004 no cells were found. The Err.number can be converted to a msg debug. Like I was expecting earlier.

    A1) Because of the Do/Loop. When it gets to Loop it goes back to Do and starts over and runs the code to create the InputBox. However, if the input is valid then code Exit Do which means it goes to the command line after Loop.

    COUNTA code: I suggest that you go back to using the Find to validate the Input. I have edited the code accordingly and it handles not finding the value.

    Q2) Alternative syntax.

    A2) Following code works. Ensure that you edit the worksheet name to your worksheet name. It finds the last used row and clears from A4 to last row column R.

    Sub ClearSheet()

    Dim lngLastRow As Long
    
    With ThisWorkbook.Worksheets("Sheet1")  ***'Edit "Sheet1" to your sheet name***
    
        lngLastRow = LastRow(.Cells)
    
        .Range(.Cells(4, "A"), .Cells(lngLastRow, "R")).ClearContents
    
    End With    
    

    End Sub

    Q3)rngTofind is a range variable a etc

    A3) Yes! Range variable can be a single cell or many cells.

    Q4) MatchCase ????

    A4) MatchCase:= True will only find where alpha characters correctly match the case of the value to be found.

    MatchCase:= False will find either upper or lower case alpha character so it does not matter how the user enters the character.
    

    I think that strictly speaking, options is actually the dialog screen where you set the arguments. In the old days we used to refer to parameters then somewhere along the line they became known as arguments so I often refer to them as parameters. (Personally I think of an argument as a discussion, sometimes heated, where people disagree but lets not get too deep into that.)

    Q5) I assumed that you must have had a template where the borders had been created over a range larger than likely to be encountered and you wanted to remove the borders below the new data. However, now that assumption appears to be incorrect so I will provide you with some code to create the borders on the new data. I assume now that you will want borders from Row 2, Column R to the bottom of the data.

    Q6) Can I write the below code as .Range.Cells(4, "O"), Cells(IngLastRow, "O") = strCity

    A6) No!. Syntax must be as I have provided.

    The date format is very flexible. Any valid date format that can be used on a worksheet. Note the following examples which you might find interesting.
    

    ddd dd mmm yyyy displays as Mon 08 Mar 2021

    dddd dd mmmm yyyy displays as Monday 08 March 2021

    Q7) And I noticed we used comma instead of colon e.g O4,O10 = strCity?

    The syntax when cells function is used is as per the following example code with the comma.

    .Range(.Cells(4, "O"), .Cells(lngLastRow, "O")) = strCity

    The colon is used in different syntax like .range("O4:O" & lngLastRow). Note that part of the address in in double quotes and it requires the last row variable to be concatenated. The previous example is much cleaner code.)

    Q8) I did not get what is LngLastRow + 1 & ":" & .Rows.Count

    A8) lngLastRow is the last row with data and because we do not want to clear the borders off the last row of data we add 1 to it which will be the firast non data row.

    Q9) To apply boarders to the used rows. I only to need to edit .Borders.LineStyle = ??? (xlnone replace with ?)

    A9) See the modified the code to clear all borders (including borders in column headers) and then re-create the borders from row cell A2 to column R and last used row.

    Q10) In rngToFind why find "*", xlFormulas, xIPart, xLPrevious instead of xIValues, xIWhole, xINext.

    A10) Yes! Asterisk is a wild card and finds any cell that contains any character/s in the cell. In other words a populated cell; not a blank cell.

    Using xlFormulas it will fnd a wild card if the cell is populated irrespective of whether it is a formula or value in the cell.

    xlPrevious. Firstly you need to understand that when Find is implemented, by default it commences from the first cell of the range to be searched. However, if the first cell is a match, it does not find it first because of xlNext or xlPrevious is telling it to get the Next or Previous; not the first cell where it starts from. So it initially skips the first cell of the range and goes to the next or previous match depending on the argument setting.

    xlNext moves forward through the range and when it gets to the end of the range it loops back to the start of the range. xlPrevious searches backwards and when it gets to the start of the range it moves to the end of the range. However, the search still commences by default from the first cell of the range. Because it goes backwards it goes to the last cell in the range (with Cells used as the range (which is the entire worksheet) it goes to the last cell on the worksheet and works backwards from there.) Therefore if searching for the last cell with data it starts from the first cell and then loops around to end of the range to search.

    Q11) Can the below public function LastRow (although its predefined function) be written as follows, if not why do we declare the variable within the variable?

    A11) We have to pass the range to be searched to the Function. In the example for your project, we pass the entire worksheet range but in another project, you might only want to find the last used row of a specific column or columns and if you pass a smaller range to it then Find only searches the range that is passed to it. Basically the Fundtion is generic to be used under many different situations and the range to search and the value to be found is passed to the function when it is called.

    Q12) Else LastRow = 1 my range starts from A4. A1 to A3 are headers should I change last row = 4?

    A12) Again it is a generic function that can be used in different projects. In your project, I assume that you will always have the column headers in row 2 and 3 so if no other data then it will always return 3 (last header row). If this creates a problem then in the main code that called the function you would handle it with a test and adjust the value if necessary. The one is mainly there becaue you cannot have a row zero. If the function returns less than 4 then you need to handle the error because no actual data on the sheet.

    Next version of code with borders. Firstly all borders are cleared from the worksheet and then the used range from A2 to P and last used row hav eht borders inserted.

    Sub MCR()

    Dim wbSource As Workbook
    
    Dim wbOutput As Workbook
    
    Dim wsOutput As Worksheet
    
    Dim wsFull As Worksheet
    
    Dim lstObj As ListObject
    
    Dim strPrompt As String
    
    Dim myInp As Variant
    
    Dim lngLastRow As Long
    
    Dim strCity As String
    
    Dim strRowRef As String
    
    strCity = "New York"
    
    Set wbSource = Workbooks("ML.xlsx")             'Assign workbook to workbook variable
    
    Set wsFull = wbSource.Worksheets("Full-View")   'Assign the worksheet to worksheet variable
    
    Set lstObj = wsFull.ListObjects("Table1")   'Assign the Table (List Object) to a List Object variable
    
    'Setting the variables as per the previous 3 lines of code, lstObj now contains the full
    
    'infomation about the Table including the Workbook name, Worksheet name and Table name
    
    Set wbOutput = Workbooks("MCR Macro.xlsm")
    
    Set wsOutput = wbOutput.Worksheets("Sheet1")    'Edit "Sheet1" to the worksheet name for the output
    
    'By using a variable for the prompt, the prompt can be altered if invalid input by User
    
    strPrompt = "Enter the number" & vbCrLf \_
    
                & "Cancel to exit and terminate processing."
    
    Do
    
        'By using default in following line if User errors in the Inlut then
    
        'User can see what was entered and correct it otherwise it will be blank
    
        myInp = Trim(VBA.Interaction.InputBox(Prompt:=strPrompt, Title:="MCR Macro", Default:=myInp))
    
        If myInp = "" Then  'If user cancels then myInp will be zero length string
    
            MsgBox "User cancelled. Processing terminated." 'Optional. Can delete this line and simply Exit
    
            Exit Sub
    
        End If
    
        'If at least one value found in the column to Filter then there will be some output.
    
        If Validate(lstObj.DataBodyRange.Columns(1), myInp) Then
    
            Exit Do 'Go to past Loop command if Valid Input
    
        Else
    
            'Change Input prompt with message re invalid input and loop back to InputBox
    
            strPrompt = "Invalid entry. Please edit the number" & vbCrLf \_
    
                        & "Cancel to exit and terminate processing."
    
        End If
    
    Loop    'If Invalid Input will loop back to Do for User to edit Input.
    
    lstObj.Range.AutoFilter Field:=1, Criteria1:=myInp
    
    'DataBodyRange is range under the column headers and Column 8 is the same as offset 7 columns.
    
    lstObj.DataBodyRange.Columns(8).SpecialCells(xlCellTypeVisible).Copy
    
    wsOutput.Range("A4").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks \_
    
        :=False, Transpose:=False
    
    lstObj.AutoFilter.ShowAllData   'Optional: Cancel filtering on the Table
    
    Application.CutCopyMode = False 'Optional: Clear copy from clipboard
    
    Application.Goto wsOutput.Range("A4")   'Optional: To Activate the worksheet with Output
    
    'Note: With / End With the groups can be nested.
    
    'First With wsOutput,
    
    'Then With .Range(.Cells(2, "A"), .Cells(lngLastRow, "Q"))
    
    'Then With .Borders(xlEdgeLeft)
    
    'Note: With Border repeated for each type of border. eg Left, Top, Bottom, Right, Inside Vertical, Inside Horizontal)
    
    With wsOutput
    
        'Next line: Call the UDF to find the last used row on the worksheet
    
        lngLastRow = LastRow(.Cells)  '.Cells is entire range of wsOutput worksheet
    
        .Range(.Cells(4, "O"), .Cells(lngLastRow, "O")) = strCity
    
        .Range(.Cells(4, "P"), .Cells(lngLastRow, "P")) = Date  'Date is the current date in VBA
    
        .Range(.Cells(4, "P"), .Cells(lngLastRow, "P")).NumberFormat = "dd-mmm-yyyy"
    
        .Range(.Cells(4, "Q"), .Cells(lngLastRow, "Q")) = "C"
    
        'Initially remove all borders
    
        .Cells.Borders.LineStyle = xlNone
    
        'Insert borders on the used range
    
        With .Range(.Cells(2, "A"), .Cells(lngLastRow, "R"))
    
            With .Borders(xlEdgeLeft)
    
                .LineStyle = xlContinuous
    
                .ColorIndex = xlAutomatic
    
                .TintAndShade = 0
    
                .Weight = xlThin
    
            End With
    
            With .Borders(xlEdgeTop)
    
                .LineStyle = xlContinuous
    
                .ColorIndex = xlAutomatic
    
                .TintAndShade = 0
    
                .Weight = xlThin
    
            End With
    
            With .Borders(xlEdgeBottom)
    
                .LineStyle = xlContinuous
    
                .ColorIndex = xlAutomatic
    
                .TintAndShade = 0
    
                .Weight = xlThin
    
            End With
    
            With .Borders(xlEdgeRight)
    
                .LineStyle = xlContinuous
    
                .ColorIndex = xlAutomatic
    
                .TintAndShade = 0
    
                .Weight = xlThin
    
            End With
    
            With .Borders(xlInsideVertical)
    
                .LineStyle = xlContinuous
    
                .ColorIndex = xlAutomatic
    
                .TintAndShade = 0
    
                .Weight = xlThin
    
            End With
    
            With .Borders(xlInsideHorizontal)
    
                .LineStyle = xlContinuous
    
                .ColorIndex = xlAutomatic
    
                .TintAndShade = 0
    
                .Weight = xlThin
    
            End With
    
        End With
    
    End With
    

    End Sub

    Function LastRow(rng As Range) As Long

    'Finds the last used row in a worksheet
    
    Dim rngToFind As Range
    
    With rng
    
        Set rngToFind = .Find(What:="\*", \_
    
                LookIn:=xlFormulas, \_
    
                LookAt:=xlPart, \_
    
                SearchOrder:=xlRows, \_
    
                SearchDirection:=xlPrevious, \_
    
                MatchCase:=False)
    
    End With
    
    If Not rngToFind Is Nothing Then
    
        LastRow = rngToFind.Row
    
    Else
    
        LastRow = 1  'If nothing found then set row one as last row
    
    End If
    

    End Function

    Function Validate(rngToSearch As Range, varToFind As Variant) As Boolean

    'This function not required when COUNTA function used in lieu
    
    Dim rngToFind As Range
    
    With rngToSearch
    
        Set rngToFind = .Find(What:=varToFind, \_
    
                LookIn:=xlValues, \_
    
                LookAt:=xlWhole, \_
    
                SearchOrder:=xlByRows, \_
    
                SearchDirection:=xlNext, \_
    
                MatchCase:=False)
    
        If Not rngToFind Is Nothing Then
    
            Validate = True
    
        Else
    
            Validate = False
    
        End If
    
    End With
    

    End Function

    Was this answer helpful?

    0 comments No comments
  2. Anonymous
    2021-03-09T16:10:15+00:00

    Thank you very much!

    The below code is all I needed.

    Q1) lngLastRow = LastRow(.Cells)

    e.g if last filled row found is 4 why we used .cells instead of .value.

    or all filled cells till row 4. I guess.

    Q2) Because it goes backwards it goes to the last cell in the range (with Cells used as the range (which is the entire worksheet) it goes to the last cell on the worksheet and works backwards from there.)

    Exactly, this raised one more question. The R column is always empty so how did all boarders apply to it is what I was thinking. Then I saw this line of code.

    With .Range(.Cells(2, "A"), .Cells(lngLastRow, "R"))

    It makes sense.

    I have another small task to do. The same code can be manipulated to the other sheet wsSource to wsOutput. But this time the range needs to be dynamic. Extra rows might be needed. It is a bit tricky.

    I can share the screenshots if you are okay with that. If not I can mark this question as solved.

    With wsOutput

        lngLastRow = LastRow(.Cells)
    
        With .Range(.Cells(2, "A"), .Cells(lngLastRow, "R"))
    

    With Selection

    .Borders(xlEdgeLeft).LineStyle = xlContinuous

    .Borders(xlEdgeTop).LineStyle = xlContinuous

    .Borders(xlEdgeBottom).LineStyle = xlContinuous

    .Borders(xlEdgeRight).LineStyle = xlContinuous

    .Borders(xlEdgeLeft).LineStyle = xlContinuous

    .Borders(xlInsideVertical).LineStyle = xlContinuous

    .Borders(xlInsideHorizontal).LineStyle = xlContinuous

    End With

    End With
    

    End With

    Function LastRow(rng As Range) As Long

    'Finds the last used row in a worksheet
    
    Dim rngToFind As Range
    
    With rng
    
        Set rngToFind = .Find(What:="\*", \_
    
                LookIn:=xlFormulas, \_
    
                LookAt:=xlPart, \_
    
                SearchOrder:=xlRows, \_
    
                SearchDirection:=xlPrevious, \_
    
                MatchCase:=False)
    
    End With
    
    If Not rngToFind Is Nothing Then
    
        LastRow = rngToFind.Row
    
    Else
    
        LastRow = 1  'If nothing found then set row one as last row
    
    End If
    

    End Function

    Was this answer helpful?

    0 comments No comments
  3. OssieMac 48,006 Reputation points Volunteer Moderator
    2021-03-10T02:17:40+00:00

    @ExcelFunTension,,

    it appears that you have already answered (or at least indicated that you understand) your own questions for Q1 and Q2 of your last post.

    I am not sure what you are referring to with your following statement.

    I have another small task to do. The same code can be manipulated to the other sheet wsSource to wsOutput. But this time the range needs to be dynamic. Extra rows might be needed. It is a bit tricky.

    Do you mean that you want to apply borders to the source Sheet? If this is what you mean then the source Sheet is a table and the Table Style should automatically expand to include additional rows. However, if this is not what you mean then I need extra information. Perhaps if you share the screen shots as you suggested showing what is required. However, it is not difficult to use the same code to apply the borders to a different worksheet/range but I will wait till I hear back from you.

    Was this answer helpful?

    0 comments No comments
  4. Anonymous
    2021-03-10T14:48:34+00:00

    Yes, Q1 and Q2 are clear.

    This is going to take a while bear with me. This is an extension to what I did before.

    I get data in CSV, I have a unique number followed by some relevant info for that number and the Column G contains the text in a single line.

    Column A to Column F...

    Column G: No, but excluded in the RU under Clause III Exemption 6(a), Clause III Exemption 6(b), Clause III Exemption 6(c), Clause III Exemption 7(a), Clause III Exemption 7(c)-IV

    What I do is introduce line breaks from the word, Clause (everything in one cell) and remove other text.

    e.g Column G (after clean up)

    Clause III Exemption 6(a),

    Clause III Exemption 6(b),

    Clause III Exemption 6(c),

    Clause III Exemption 7(a),

    and Clause III Exemption 7(c)-I

    screenshot

    Image

    Q1) Is there a efficient way to do the above task for about 800 numbers.

    Now once I have the data transformation done for all the numbers.

    I want to populate it as I did before from wsSource to wsOutput in to the next sheet (sheet screenshot) but this time I plan to use the range of numbers directly (like an array) to pull in the data to the templates. I want to drop the input box feature because a separate workbook needs be created for each number nonetheless.

    In other words, my input data for wsSource is as below (I would select the range $A$2:$A50). I want the macro to run on all numbers and save as the wsOutput workbook with the respective unique number in Column A and description of the number Column B as the file name.

    e.g

    888890

    777890

    888909

    789078

    1234567T89

    1246557Y67

    etc

    The transformed CSV data has to go into Category 1 table (below screenshot) based on a filter e.g Category 1 in wsSource.

    Number of rows has to be dynamic depending on the output numbers.

    I plan to delete all the empty rows in the template and keep it as shown in Category 2 & 4, that way I don't have to worry about deleting the left out rows. For the sake of demonstration I left those blank rows.

    Image

    Same repeats for Category 2 with the same unique numbers, if at all there are any entries with Category 2 filter. If no entries macro would enter N/A (as shown in Category 4)

    The input numbers source is same as above

    e.g

    888890

    777890

    888909

    789078

    1234567T89

    1246557Y67

    etc

    In case of Category 3, with Category 3 filter applied, rows can be merged when they match. Row content matches until Column E and Column F values has to be left out in separate cells as shown in the screenshot.

    In the end for Category 4 with the same unique numbers, if at all there are any entries with Category 4 filter. Macro populates it. If no entries macro would enter N/A (as shown in Category 4)

    The input numbers source is same as above

    e.g

    888890

    777890

    888909

    789078

    1234567T89

    1246557Y67

    etc

    Was this answer helpful?

    0 comments No comments
  5. OssieMac 48,006 Reputation points Volunteer Moderator
    2021-03-11T00:05:27+00:00

    Your initial question is constantly expanding to include more requirements.

    I don't really understand all of your last post. I am happy to continue assisting you but I need to be able to see the entire picture from start to end. ie. I need a copy of the initial data (if I am understanding correctly it is a csv file). I also need a dummy Output workbook with the data displayed as required before saving. If you have sensitive data in the workbook then replace with dummy data.

    In your previous post I can't reconcile the following with the screen shot.

    Column G: No, but excluded in the RU under Clause III Exemption 6(a), Clause III Exemption 6(b), Clause III Exemption 6(c), Clause III Exemption 7(a), Clause III Exemption 7(c)-IV

    What I do is introduce line breaks from the word, Clause (everything in one cell) and remove other text.

    e.g Column G (after clean up)

    Clause III Exemption 6(a),

    Clause III Exemption 6(b),

    Clause III Exemption 6(c),

    Clause III Exemption 7(a),

    and Clause III Exemption 7(c)-I

    After inserting the line breaks, line 5 is prefixed with "and" and the end of line 5 is missing the last character ("V"). Is the "and" really required?

    Then your screen shot is changed from above. ("and" omitted from line 5 and line 6 introduced and prefixed with "and". Line 6 text not anywhere in the initial Column G value).

    I think that I understand that you want to loop through the numbers in column A and produce a workbook for each unique number. It is easy enough to create a unique list of the numbers from column A and can create a loop and save and close each created workbook as per you requirement of workbook name (respective unique number in Column A and description of the number Column B as the file name.)

    If you can upload the workbooks to OneDrive then I will take a look at the entire project. I am sure you have heard the saying "A picture is worth a thousand words". I think that a copy of a workbook is worth much more than that.

    Guidelines to upload a workbook on OneDrive. (If you already use OneDrive and your process for saving to it is different then you can probably start at step 8 to get the link but please zip the file before uploading.)

    Sharing links to business OneDrive often does not work because the business has applied security measures that prevent this. Some people take a copy of the workbook home and upload from their private OneDrive.

    1. Zip your workbooks. Do not just save an unzipped workbook to OneDrive because the workbooks open with On-Line Excel and the limited functionality with the On-Line version causes problems.
    2. To Zip a file: In Windows Explorer Right click on the selected file and select Send to -> Compressed (zipped) folder). By holding the Ctrl key and left click once on each file, you can select multiple workbooks before right clicking over one of the selections to send to a compressed file and they will all be included into the one Zip file.
    3. Do not use 3rd party compression applications because I cannot unzip them. I do not clog up my computer with 3rd party apps when there are perfectly good apps supplied with windows.
    4. Go to this link. https://onedrive.live.com
    5. Use the same login Id and Password that you use for this forum.
    6. Select Upload under the blue bar across the top and browse to the zipped folder to be uploaded.
    7. Select Open (or just double click). (Be patient and give it time to display the file after initially seeing the popup indicating it is done.)
    8. Right click the file name in OneDrive.
    9. Select Share.
    10. Click the link icon (Looks like chain links) at the bottom left of the dialog (Just above "Copy link").
    11. Click Copy button.
    12. Change back to this forum and click the "Insert Hyperlink" icon at top of the posting editor (Icon looks like chain links).
    13. Right click in the Web address field and right click and paste (or just Ctrl V to paste).
    14. Click "Insert" Button.

    Was this answer helpful?

    0 comments No comments