0

I want to either delete the validation of a cell or set an empty validation if the Target of Worksheet_Change is deleted.

The Target cell is a merged cell which also has a xlValidateList. If I choose one of the values, my code runs ok, but when I delete the content of this cell, it doesn't change the validation of the other cell.

I think it comes from the merging of the cells or because it has a xlValidateList

I tried to check IsEmpty(Target) but its always FALSE, even if I delete the content of the Target cell

My code so far:

Private Sub Worksheet_Change(ByVal Target As range)

Dim lengthFromCell As range
Dim lengthToCell As range

' only execute when on column F and
If Target.Column <> 6 Or Target.Cells.Count > 1 Then Exit Sub

Set lengthFromCell = Target.Offset(0, 1)
Set lengthToCell = lengthFromCell.Offset(1, 0)

' Delete contents of "length" cells
lengthFromCell.value = ""
lengthToCell.value = ""
    
    If Target.value = "A" Then
        With Target.Offset(0, 1).Validation
            .Delete
            .Add Type:=xlValidateList, _
                AlertStyle:=xlValidAlertStop, _
                Operator:=xlBetween, _
                Formula1:="1, 2, 3"
            .IgnoreBlank = True
            .InCellDropdown = True
            .ErrorTitle = ""
            .ErrorMessage = ""
            .ShowError = True
        End With
    ElseIf Target.value = "B" Then
        With Target.Offset(0, 1).Validation
            .Delete
            .Add Type:=xlValidateList, _
                AlertStyle:=xlValidAlertStop, _
                Operator:=xlBetween, _
                Formula1:="4, 5, 6"
            .IgnoreBlank = True
            .InCellDropdown = True
            .ErrorTitle = ""
            .ErrorMessage = ""
            .ShowError = True
        End With
    Else
'here either delete the validation or at least set it to 0 or ""
        With Target.Offset(0, 1).Validation
            .Delete
            .Add Type:=xlValidateList, _
                AlertStyle:=xlValidAlertStop, _
                Operator:=xlBetween, _
                Formula1:="0, 0, 0"
            .IgnoreBlank = True
            .InCellDropdown = True
            .ErrorTitle = ""
            .ErrorMessage = ""
            .ShowError = True
        End With
    End If
End Sub

EDIT:

"Target" is the target from Worksheet_Change which is of type Range. So it is the merged cell in which my dropdown list with values "A and B" are in.

picture of cells

The main problem is that my code doesn't recognice the deletion of the value "A" in merged cells, but in single cells it does.

omnomnom
  • 190
  • 1
  • 12
  • 1
    Please, try `If Target.value = "" then` – FaneDuru Nov 15 '21 at 15:09
  • FYI you can remove a bunch of repetition from your code by creating a separate "AddValidation" sub and passing in `Target.Offset(0 ,1)` and the value for `Formula1` – Tim Williams Nov 15 '21 at 18:09
  • @FaneDuru ```If Target.value = ""``` also does nothing. If I have my Target in a single cell, It works, but not with the merged cells. The same happens with ```IsEmpty(Target)``` – omnomnom Nov 16 '21 at 12:48
  • I am afraid that a "Target **cell**" means something different. When you talk about `Target` you talk about a `Range`. Anyhow, I cannot understand what you mean, only reading your question. I suppose that editing the question and placing two pictures (existing and after) we will maybe understand what you try saying... – FaneDuru Nov 16 '21 at 12:54
  • @FaneDuru I edited it. I hope its better now. – omnomnom Nov 16 '21 at 13:06
  • @TimWilliams also ErrorTitle and ErrorMessage are different. I don't know if it is worth it. But thanks for the proposal. – omnomnom Nov 16 '21 at 13:08
  • Do you want saying that `Target` in the picture should be "G4:G5"? If so, what "validation of the other cell" does mean? Another "H4:H5" merged cell? – FaneDuru Nov 16 '21 at 13:12
  • @FaneDuru No. Target is "F4:F5". In this merged cell I delete the Value "A". I want my code to recognice the deletion. Something like ```If Target.value = "" Then``` or ```IsEmpty(Target)```. But this does not work with merged cells. – omnomnom Nov 16 '21 at 13:26
  • Do you clean the merged cells range **content**, or unmerge cells, too? Now, is "G4:G5" merged, too, or as it looks in the picture: Only "G4"? – FaneDuru Nov 16 '21 at 13:32
  • No, I just press "Del". But the merged cells do not count as empty it seems. not for Target.value = "" nor for IsEmpty() – omnomnom Nov 16 '21 at 13:36
  • You did not answer the question regarding "the other cell"... – FaneDuru Nov 16 '21 at 13:45
  • Should be self explanatory from my code. It's the ```Target.Offset(0,1)``` So "the other cell" does mean "G4" where I change the validation based on the conditions in cells "H4:H5". But those cells are not really of interest for the problem. – omnomnom Nov 16 '21 at 14:06

2 Answers2

1

Please, try the next function:

Function isMergeEmpty(rng As Range) As Boolean
   Dim x As String
   On Error Resume Next
      x = rng.value
      If err.Number <> 0 Then
            isMergeEmpty = True
      End If
    On Error GoTo 0
End Function

It can be called from the event in this way:

Private Sub Worksheet_Change(ByVal Target As Range)
    If isMergeEmpty(Target) Then 
        'do here what you need...
        MsgBox "Empty merge cell..."
    End if
End Sub

Edited:

Please, test the next full solution:

Private Sub Worksheet_Change(ByVal Target As range)

Dim myList As Object
Set myList = CreateObject("Scripting.Dictionary")
myList.Add "Einseitig", 1
myList.Add "Doppelseitig", 2
myList.Add "Halbzylinder", 3

Dim lengthFromCell As range
Dim lengthToCell As range

' only execute when on column F and no more of one cell (IF Target is NOT merged):
If Target.Column <> 6 Or (Target.Cells.Count > 1 And Target.MergeCells = False) Then Exit Sub

Set lengthFromCell = Target.Offset(0, 1)
Set lengthToCell = lengthFromCell.Offset(1, 0)
Application.EnableEvents = False 'to avoid the event running three times
                                 'it will also be triggered for each of the following lines:
' Delete contents of "length" cells
lengthFromCell.value = ""
lengthToCell.value = ""
 
    If isMergeEmpty(Target) Then 'it should be first, in order to avoid `Target.value` which returns an error for an empty merged range
        With Target.Offset(0, 1).Validation
            .Delete
            .Add Type:=xlValidateList, _
                AlertStyle:=xlValidAlertStop, _
                Operator:=xlBetween, _
                Formula1:="0, 0, 0"
            .IgnoreBlank = True
            .InCellDropdown = True
            .ErrorTitle = "Werte ausserhalb Bereich"
            .ErrorMessage = "Einseitig bla blub"
            .ShowError = True
        End With
    ElseIf Target.value = "Einseitig" Then
        With Target.Offset(0, 1).Validation
            .Delete
            .Add Type:=xlValidateList, _
                AlertStyle:=xlValidAlertStop, _
                Operator:=xlBetween, _
                Formula1:="1, 2, 3"
            .IgnoreBlank = True
            .InCellDropdown = True
            .ErrorTitle = "Werte ausserhalb Bereich"
            .ErrorMessage = "Einseitig bla blub"
            .ShowError = True
        End With
    ElseIf Target.value = "Doppelseitig" Then
        With Target.Offset(0, 1).Validation
            .Delete
            .Add Type:=xlValidateList, _
                AlertStyle:=xlValidAlertStop, _
                Operator:=xlBetween, _
                Formula1:="4, 5, 6"
            .IgnoreBlank = True
            .InCellDropdown = True
            .ErrorTitle = "Werte ausserhalb Bereich"
            .ErrorMessage = "Einseitig bla blub"
            .ShowError = True
        End With
    ElseIf Target.value = "Halbzylinder" Then
        With Target.Offset(0, 1).Validation
            .Delete
            .Add Type:=xlValidateList, _
                AlertStyle:=xlValidAlertStop, _
                Operator:=xlBetween, _
                Formula1:="7, 8, 9"
            .IgnoreBlank = True
            .InCellDropdown = True
            .ErrorTitle = "Werte ausserhalb Bereich"
            .ErrorMessage = "Einseitig bla blub"
            .ShowError = True
        End With
    End If
    Application.EnableEvents = True
End Sub
Function isMergeEmpty(rng As range) As Boolean
   Dim x As String
   On Error Resume Next
      x = rng.value
      If Err.Number <> 0 Then
            isMergeEmpty = True
      End If
    On Error GoTo 0
End Function

Now, the main problem of our code as it was consisted in the way it was exited, in case of more then one cell. VBA has a peculiar behavior when treats a merged range having a value and *an empty such merged range, in terms of Cells.Count property. You must know that TargetCells.Count returns 1 if it refers a merged range having a value and **the number of cells in the mergeArea if it is empty. That's why the need to add Or (Target.Cells.Count > 1 And Target.MergeCells = False). To exclude from exiting cases of empty merged Target. Your code, as it was, exited on this line and the supplied function was never called.

Then, in order to avoid Target.Value = ..., which returns an error in case of an empty merged Target the checking for an empty Target must be first.

I also optimized the code in order to avoid the event to be triggered three times, instead of one.

If something still unclear, please do not hesitate to ask for clarifications. I alo commented the specific lines inside the code...

Second Edit:

I thought that you created an unmerged example only to show the different behavior against the merged one. But if you need the code to also work in such a case, another condition must be add at the end. Then, the code cam become more compact as the next one:

Private Sub Worksheet_Change(ByVal Target As range)
 Dim myList As Object: Set myList = CreateObject("Scripting.Dictionary")

 myList.Add "Einseitig", 1: myList.Add "Doppelseitig", 2: myList.Add "Halbzylinder", 3

 Dim lengthFromCell As range, lengthToCell As range, strFormula As String

' only execute when on column F and Target.CellsCount =1 (excluding the merged Target):
If Target.Column <> 6 Or (Target.Cells.Count > 1 And Target.MergeCells = False) Then Exit Sub

Set lengthFromCell = Target.Offset(0, 1): Set lengthToCell = lengthFromCell.Offset(1, 0)

Application.EnableEvents = False
' Delete contents of "length" cells
lengthFromCell.value = "": lengthToCell.value = ""
 
    If isMergeEmpty(Target) Then
        strFormula = "0, 0, 0"
    ElseIf Target.value = "Einseitig" Then
        strFormula = "1, 2, 3"
    ElseIf Target.value = "Doppelseitig" Then
        strFormula = "4, 5, 6"
    ElseIf Target.value = "Halbzylinder" Then
        strFormula = "7, 8, 9"
    ElseIf Target.value = "" Then 'for the case of not merged Target:
        strFormula = "0, 0, 0"
    End If
    If strFormula <> "" Then
        With Target.Offset(0, 1).Validation
            .Delete
            .Add Type:=xlValidateList, _
                AlertStyle:=xlValidAlertStop, _
                Operator:=xlBetween, _
                Formula1:=strFormula
            .IgnoreBlank = True
            .InCellDropdown = True
            .ErrorTitle = "Werte ausserhalb Bereich"
            .ErrorMessage = "Einseitig bla blub"
            .ShowError = True
        End With
    End If
    Application.EnableEvents = True
End Sub
FaneDuru
  • 38,298
  • 4
  • 19
  • 27
  • I did. On deleting the cells content, the functions Err.Number always returns 0. So the function always returns FALSE. – omnomnom Nov 17 '21 at 07:36
  • It does not even trigger the function on deleting directly in the cell. Even if I press enter after the deletion it does not trigger. If I delete the value in the Formula area above my table, then pressing enter, it triggers. So it seems that ```Worksheet_Change()``` does not recognice the deletion if it is performed with the "Del" key directly in the table. This only applies to merged cells! – omnomnom Nov 17 '21 at 07:53
  • @omnomnom I cannot get you... I cannot imagine how you used it. When the code try to 'extract` the value of an empty merged group of cells (`x = rng.value`), it returns an error, what you were complaining of. This error is caught by `If err.Number <> 0 Then`. What you say about `Worksheet_Change()` no make any sense, neither... It behaves exactly the opposite: Changing a formula result is not triggered by `Change` event. It is triggered only by `Calculate` event. If not something confidential in your workbook, if you send it to me, when I will have some time, I can try understanding. – FaneDuru Nov 17 '21 at 08:27
  • I sent it to you. Maybe my workbook is broken or something. I also tried it with ```If Not Intersect() Is Nothing``` but with no success. It just seems that deleting on merged cells the change event is not triggered. – omnomnom Nov 17 '21 at 08:52
  • I of course testet it with your function but I progressed testing myself. The pseudo function is a residue of my tests with If Not Intersect() Is Nothing.. I think I should test it in a fresh workbook then. – omnomnom Nov 17 '21 at 09:24
  • @omnomnom You should tell me that you do not use the function and what problem you have! Testing without feedback, means nothing! A fresh workbook will not bring anything good. Your event has a problem which must be corrected. I will do it when I will have some time. If you want trying, I do not have a problem with that. – FaneDuru Nov 17 '21 at 09:31
  • @omnomnom Please test the solution I posted after editing the answer and send some feedback. I will be driving in the next hour and only can **see** your comments. – FaneDuru Nov 17 '21 at 09:41
  • Ok. Now this works actually. Was it the deactivation of the events or just because its the first If statement now? Take your time to answer. – omnomnom Nov 17 '21 at 10:34
  • Please, look to rhe line exiting the event, if Target.count 》1... I will explain in details when I will be back in my office. – FaneDuru Nov 17 '21 at 10:45
  • Please, test the edited answer. The **second Edit** too and send some feedback. – FaneDuru Nov 17 '21 at 13:46
0

I have come across the same issue, except I do not have Merged cells with Validation code. To do the check in my Sheet.Change Event, I do this (pseudo) code:

        If IsArray(Target.Value) Then      ' Detect if multiple rows are Pasted/Deleted
            ' Do stuff for multiple cells
        Else
            ' Do stuff for single cells
        End If

or this one, which takes into consideration if an 'Area' is being changed:

        If Selection.Rows.Count * Selection.Columns.Count > 1 Then
            ' Do stuff for multiple cells (rows and or columns)
        Else
            ' Do stuff for single cells
        End If
        'courtesy: @comintern via https://stackoverflow.com/questions/36199529/detect-on-worksheet-change-if-user-is-deleting

Hope it helps, at least someone out there...