My sub routine
Sub Worksheet_Change(ByVal Target As Range)
MsgBox Target.value
End Sub
Throws type mismatch error when I refresh connection to database. I have actually connected excel to database.
What is the value of Target.value when I refresh database connection?
Type Mismatches are usually (I stress usually) easy to debug. Without knowing exactly what Target is, it's difficult to say why the error happens.
My first guess is that the range spans more than one cell. For example, this code also gives a "Type Mismatch" error:
Sub test()
Dim r As Range
Set r = Range("A1:a2")
MsgBox r.Value
End Sub
If the range is a single cell, then maybe it's in error or some other "Range Type".
I found the following code which will help you determine a cell's type.
Related
I was knowing before how create that code in case of determining a specific array to implement a function in it:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not Intersect(Target, Range("A1:O7000")) Is Nothing Then
MsgBox "Hi"
End If
End Sub
So Intersect here works only when I write inside Argument2 Range function.
I don't want to determine whole that array. When I want to develop this code by this shape:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim SafeTbl As ListObject
Set SafeTbl = ListObjects("Safe")
If Not Intersect(Target, SafeTbl.Range.Address) Is Nothing Then
MsgBox "Hi"
End If
End Sub
I find this Type mismatch compile error:
I don't know why this error exists. While I see that my development is making same as previous code does. As this code is determining only array has data.
As suggested in the comments, .Address is a string. The Intersect method requires ranges as the parameters, not the text of the range address, which you are currently providing.
The Type mismatch compile error is telling you that the "variable or property isn't of the correct type" (https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/type-mismatch-error-13)
Microsoft says:
[Application.Intersect method (Excel)] Returns a Range object that
represents the rectangular intersection of two or more ranges.
To be explicit, this means your code needs changing to this:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim SafeTbl As ListObject
Set SafeTbl = ListObjects("Safe")
If Not Intersect(Target, SafeTbl.Range) Is Nothing Then
MsgBox "Hi"
End If
End Sub
More can be read about the Intersect method here: https://learn.microsoft.com/en-us/office/vba/api/excel.application.intersect
And also more about the Range property here: https://learn.microsoft.com/en-us/office/vba/api/excel.range.range
Update
As #BigBen correctly points out, in your case, we are actually referring to the ListObject.Range property, so the further information on this is here: https://learn.microsoft.com/en-us/office/vba/api/excel.listobject.range
How can I resolve the type mismatch error (indicated)?
If I want to restrict the sub to the specified ranges, why would changing If Not Intersect to If Intersect exit the sub?
Private Sub Workbook_SheetBeforeDoubleClick(ByVal sH As Object, ByVal Target As Range, Cancel As Boolean)
' Exclude specified ranges
Dim rExcl(1) As Range, i As Integer, r As Range
Set rExcl(0) = Range("Table1"): Set rExcl(1) = Range("Table2")
For i = 0 To 1
For Each r In rExcl(i)
If r.Parent Is sH Then
If Not Intersect(Target, r) Is Nothing Then Exit Sub ' Type mismatch error
End If
Next
Next
End Sub
It seems that the purpose of the code posted is to validate if the user double-clicked a cell within any of the Tables (i.e.: Table1 or Table2), if so then Exit Sub.
In regards to the questions:
1. How can I resolve the type mismatch error (indicated)?
If Not Intersect(Target, r) Is Nothing Then Exit Sub ' Type mismatch error
Unfortunately, this error cannot be reproduced. This error is triggered when the data type of a variable differs to what is required. In this case it seems "almost" impossible because:
Intersect expects ranges and both variables (Target and r) are defined as ranges.
Intersect returns an object (range) which is what Is Nothing is expecting.
Intersect could also return an Error when the ranges have different parents, but that situation is already taken care by this line If r.Parent Is Sh Then.
The proposed solution includes a method to debug this error when it happens.
2. If I want to restrict the sub to the specified ranges, why would changing If Not Intersect to If Intersect exit the sub?
This is happening because the code posted is validating the ranges cell by cell, therefore if the user double-clicked the last cell of the table then the code compares the first cell and because there is no intersection the code exits the sub.
Bear in mind that the purpose is to validate if the double-clicked cell belongs or not to any of the tables ( i.e.: “ranges intersection”, if one cell intersect or not with a range, then the entire range intersects or not), as such there is no need to validate each cell, instead validate the entire range at once.
Proposed Solution:
Note that the ERR_Intersect subroutine should be just temporary, it is include to help analyze the mismatch error.
Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
Dim rExcl(1) As Range, vRng As Variant
Set rExcl(0) = Range("Table1")
Set rExcl(1) = Range("Table2")
For Each vRng In rExcl
Rem Validate Worksheet
If vRng.Parent Is Sh Then
Rem Validate Target
On Error Resume Next
If Not Intersect(Target, vRng) Is Nothing Then
blErr = Error.Number <> 0
On Error GoTo 0
If blErr Then GoTo ERR_Intersect
Exit Sub
End If
On Error GoTo 0
End If: Next
Exit Sub
ERR_Intersect:
Debug.Print vbLf; "Error: "; Err.Number; " - "; Err.Description
Debug.Print "Object"; Tab(11); "TypeName"; Tab(21); "Address"; Tab(31); "Parent"
Debug.Print "Target"; Tab(11); TypeName(Target);
Debug.Print Tab(21); Target.Address(0, 0);
Debug.Print Tab(31); Target.Parent.Name;
Debug.Print
Debug.Print "vRng"; Tab(11); TypeName(vRng);
Debug.Print Tab(21); vRng.Address(0, 0);
Debug.Print Tab(31); vRng.Parent.Name;
Debug.Print
MsgBox "Error: " & Err.Number & " - " & Err.Description & vbLf & _
vbTab & "See Immediate Window for details."
Exit Sub
End Sub
Your code works without any problem in the way you presented and it will also work in the way you try understanding, but with a different meaning, respectively:
You should understand that Intersect returns a 'Range' and the above code checks if this Range exists. In words, this part should be understood as "If the two ranges are intersecting".
This part If Intersect(Target, r) Is Nothing Then Exit Sub means "If the two ranges are not intersecting" (such an eventual intersection does not exist).
No any 'Type mismatch' should exist in both mentioned variants, if you are referring to real tables. It may appear if you named a different object (not a range) as 'TableX'...
Please, try inserting the next code line:
Debug.Print TypeOf rExcl(0) Is Range, TypeOf rExcl(1) Is Range: stop
after:
Set rExcl(0) = Range("Table1"): Set rExcl(1) = Range("Table2")
What does it return in Immediate Window?
Edited:
You could not 'reproduce the error in Debug.Print' because that line is not even reached...
There is a conflict in your workbook. There is the Workbook event you show us in the question and another Worksheet_BeforeDoubleClick event which tries closing the Excel application if the double clicked cell is the one you claim as being 'strange'...
The sheet event is triggered first and the Workbook one is not triggered anymore, since the code tries quitting Excel application. Try put Exit Sub as the first code line in the Worksheet event and try the double click again.
Nothing wrong will happen after that...
I am new to vba and I am running into a Type mismatch error when I delete multiple cells in my workbook, and it is failing at the If statement here:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Value = "Multiple Choice - Multiple Answer" Then
MsgBox "You selected MC-MA"
End If
End Sub
I am wondering if there's a way to check if a user is deleting contents of a cell and NOT run this if statement if that is the case?
I have tried If Trim(Target.Value) <> Empty but it throws the error I'm guessing because Im trying to run an If statement on a value that doesn't exist.
I expect If Trim(Target.Value) <> Empty to make it skip the above code but it throws the Type mismatch error.
Try the SelectionChange Event like this:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim cel As Range
For Each cel In Target
If cel.Value = "Multiple Choice - Multiple Answer" Then
MsgBox "You selected MC-MA"
End If
Next
End Sub
In Change event even if you try and check cells one by one, you won't spot the cell with that match because the code runs after the delete has been executed. So by the time it comes to the If statement, the cell is already blank.
I figured out a way around it. If I just do an If statement that checks if Target.Count = 1 then run the code it works!
I have the following worksheet function saved in the Sheet1 (DataInput) module of VBA
Sub worksheet_change(ByVal target As Range)
Set target = Range("F67")
If target.Value = "YES" Then
Call ThisWorkbook.Red_Macro_Text
End If
End Sub
This code calls the following code in ThisWorkbook
Public Sub Red_Macro_Text()
ThisWorkbook.Worksheets("DataInput").Range("B68").Value2 = ThisWorkbook.Worksheets("Text").Range("B3").Value2
End Sub
The purpose of the code is as follows:
The code uses an event trigger to watch for changes to worksheet ‘datainput’ cell F67.
Whenever the user selects ‘YES’ from a drop down menu in cell F67 it calls the subroutine in ThisWorkbook.
The code uses the range function to assign the value of 'text' worksheet B3 into 'datainput' worksheet B68 cell.
The trigger event does call the code and the content of B3 does get transferred to B68 however following this I then get the error message:
Run-time error ‘-2147417848 (80010108)’: Automation error The object
invoked has disconnected from its clients.
Please note I do not want to use an IF statement in excel to achieve this as I am trying to automate the process in VBA.
I have been searching for a solution to this problem for some time without success.
Does anyone know how to solve this problem as I have reached the limit of my understanding!
All help is appreciated
It doesn't make sense to Set target = Range("F67") because it is already retrieved as parameter ByVal target As Range
If you want to run the code only if F67 changes use the following instead:
Sub worksheet_change(ByVal Target As Range)
If Not Intersect(Target, Target.Parent.Range("F67")) Is Nothing Then
If Target.Parent.Range("F67").Value = "YES" Then
ThisWorkbook.Red_Macro_Text
End If
End If
End Sub
Note that Call is not needed to call a macro.
Try
Sub worksheet_change(ByVal Target As Range)
If Target.Address = Range("F67").Address Then
If Target.Value = "YES" Then
Call ThisWorkbook.Red_Macro_Text
End If
End If
End Sub
I am trying to learn a bit of VB and there is an exercise to change a value and check the previous value and if it is different do something. I eventually found a solution I could understand and get to work from : How do I get the old value of a changed cell in Excel VBA? - solution 4.
My code is:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cell As Variant
For Each cell In Target
If previousRange.Exists(cell.Address) Then
If Not Application.Intersect(Target, Me.Range("B12:B12")) Is Nothing Then
If previousRange.Item(cell.Address) <> cell.FormulaR1C1 Then
cell.Interior.ColorIndex = 36
End If
End If
End If
Next
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim cell As Variant
Set previousRange = Nothing 'not really needed but I like to kill off old references
Set previousRange = CreateObject("Scripting.Dictionary")
For Each cell In Target.Cells
previousRange.Add cell.Address, cell.FormulaR1C1
Next
End Sub
The next exercise was to add a button and perform an action depending on the user's response. So I added:
Private Sub CommandButton2_Click()
Dim currentValue, message As Integer
currentValue = Range("C3").Value
message = MsgBox("Click OK to add 1, cancel to leave", vbOKCancel, "Addition")
If message = 1 Then
Range("C3").Value = currentValue + 1
End If
End Sub
The problem I have is that the button adds one to C3 but then falls over at the If previousRange.Exists(cell.Address) statement on the Worksheet_Change sub.
All the code is defined on Sheet1, but I do not seem to have a previous value generated for my button value(C3). How do I generate the previous value, or what am I missing?
Regards
J
As I seemed to have made things worse I have created a new spreadsheet with just the change events code and nothing else to try and simplify the problem. So the complete code I have now is:
Option Explicit
Dim previousRange As New Dictionary
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cell As Variant
For Each cell In Target
If previousRange.Exists(cell.Address) Then
If Not Application.Intersect(Target, Me.Range("B12:B12")) Is Nothing Then
If previousRange.Item(cell.Address) <> cell.FormulaR1C1 Then
cell.Interior.ColorIndex = 36
End If
End If
End If
Next
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim cell As Variant
Set previousRange = Nothing 'not really needed but I like to kill off old references
Set previousRange = CreateObject("Scripting.Dictionary")
For Each cell In Target.Cells
previousRange.Add cell.Address, cell.FormulaR1C1
Next
End Sub
Now if I change the B12 cell, the previousRange As New Dictionary code is highlighted, and a message states "Compile error:User defined type not defined".
This code used to work before I introduced the message box and made a subsequent change. Must be user error. Can you help?
Regards J.
The .Exists method is used on dictionary objects, like the example you've cited. But I don't see where you've declared a dictionary object in your code. Maybe you're missing a declaration statement for it?
Dim previousrange As New Dictionary
Please note that, like the solution you've cited, you'll need to declare this before the sub routine. Also, you'll need to enable the Microsoft Scripting Runtime. Here's how:
In the VBA editor, go to the Tools menu and click on References...
In the Available References list box, scroll down until you see Microsoft Scripting Runtime. Make sure its check box is checked.
Click OK.
Now you're able to use Dictionary objects.