I'm trying to pop up a warning dialog if one of the cells in a range is blank.
Excel is popping up the warning when a cell is populated by a data validation drop down menu.
The code works on a range that doesn't contain data validation drop downs.
All data are strings and the cells are formatted as "General".
ActiveSheet.Range("I3:I10").Select
For Each cell In Selection
If cell.Value = "" Then
If MsgBox("Customer information missing. Okay to proceed; Cancel to stop and fill in missing information.", vbOKCancel) = vbCancel Then
Exit Sub
Else
Exit For
End If
End If
Next
The issue seems to stem from cells being merged across multiple columns, so Excel is checking each cell I3:K10 and finding J3:K10 blank. Unmerging the cells isn't an option.
If a cell is set up with data validation using a list and one of the cells in the list range is blank, the cell will be considered blank even if the user has selected the blank cell from the drop-down. However, if you also want to check if the cell is empty and does not have data validation, you can use the following (thanks to Determine if cell contains data validation)
Dim blnValidation As Boolean
Dim cell As Range
ActiveSheet.Range("I3:I10").Select
For Each cell In Selection
If cell.Value = "" Then
blnValidation = False
On Error Resume Next
blnValidation = Not IsNull(cell.Validation.Type)
On Error GoTo 0
If Not blnValidation Then
If MsgBox("Customer information missing. Okay to proceed; Cancel to stop and fill in missing information.", vbOKCancel) = vbCancel Then
Exit Sub
Else
Exit For
End If
End If
End If
Next
So, I was wrong with my initial guess, but the cure still would've worked.
How to avoid using Select in Excel VBA
The selection is actually Range("I3:K10"). So after it checks column I it moves onto Column J and then K
There a COUNTBLANK function but in this case you're probably better off with the COUNT Application.WorksheetFunction.
You could replace your loop with:
If Application.WorksheetFunction.Count(Range("I3:I10")) < 8 Then
'missing data - notify user here
End If
Related
I am trying to create a table where when I change the status for a task in Done in a cell then in a different I will have the timestamp of the "Done" status.
So, in attached picture in column D I have a Dropbox with "Done", "Ongoing" and "On hold". In column E I used this formula to put the timestamp for Done status:
=IF(D4="DONE",IF(E4="DONE",E4,NOW()),"").
Timestamp is working, so that is fine, but when I change another task that was ongoing into "Done", then the timestamp modifies for the whole column. and I don't want that. I want for each cell to have an independent time stamp like I have in column B. In column B, I used the same formula correlating with cell C, when data is entered in cell B, then timestamp will appear in cell C.
The problem is that the formula is recalculated at any time that Excel thinks it should be recalculated, and therefore the timestamp is updated.
You could use some VBA code instead. Put a Change-Eventhandler into the code of the sheet and set the timestamp if a cell in column D is changed to "Done". Your code could look like that:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
' Check if cell in column D was changed, if not, we're done.
If Intersect(Target, Columns("D")) Is Nothing Then Exit Sub
Application.EnableEvents = False ' Disable events to prevent recursive call of change
On Error GoTo change_exit ' Ensure that events are enabled even if error occurs
' Check if more than one cell was changed (eg by using cut and paste)
If Target.Count > 1 Then
MsgBox "Please change only one cell at a time"
Application.Undo
GoTo change_exit
End If
' Now check if value was changed to "Done" and set timestamp
If LCase(Target.Value) = "done" Then
Target.Offset(0, 1) = Now
End If
change_exit:
Application.EnableEvents = True
End Sub
I'm sorry this question may look like antoher ones, but I am new in VBA and struggle to get a proper code...
I would like to protect some data after they were verified. For exemple, I have data in Column B (or whatever column) and I check them in comparaison to manuscrit raw data. I would like to have a cell in that column where I say "Yes" to testify this was checked. After entering "Yes", I would like that all cells in the colum become locked.
I've found a code to lock an entire row (Lock rows in Excel using VBA), but whatever i try, i'm not able to modifiy it to work for a variable entire column (only to lock specific column, I'm not able to lock the column where "Yes" is typed ...)
Could someone help me ?
Thanks !
Maybe this solution can help:
Step 1: select all cells in a sheet. Goto properties (cell format) -> security and deaktivate the checkbox for lock cells (see picture below).
Step 2: protect the sheet with a password. In my example I used "billytalent".
Step 3: copy the following code into the code-area of the sheet. Therefore open the Visual Basic Editor. On the left side you will find a list with your sheets. Double click on the sheet where you want to lock cells with entry "yes". Copy the procedure into the code-area.
Private Const PASSW As String = "billytalent"
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cell As Range
For Each cell In Target
'only do something, if input is in row 2
If cell.Row = 2 Then
'only do something, if someone write yes in a cell
If cell.Value = "yes" Then
'deaktivate the protection of the sheet
ActiveSheet.Unprotect Password:=PASSW
'lock the cells in the column
ActiveSheet.Columns(cell.Column).Locked = True
'activate the protection
ActiveSheet.Protect Password:=PASSW, userinterfaceonly:=True, AllowFiltering:=True, AllowFormattingCells:=True, AllowFormattingRows:=True, AllowFormattingColumns:=True
ActiveSheet.EnableOutlining = True
End If
End If
Next
End Sub
You can tweak the code you're looking at there a little and I think it will do what you want. Make sure before you start this that you set all the cells on the sheet to unprotected.
This is set to check row 3 of the sheet for Yes. Change the value on the second line if you need to.
Private Sub Worksheet_Change(ByVal Target As Range)
row_to_check = 3 ' Checking row 3 for "Yes"
If Intersect(Target, Me.Rows(row_to_check)) Is Nothing Then Exit Sub ' exit early if row 3 wasn't changed
Me.Unprotect ' unprotect the sheet
For Each r In Target.EntireColumn.Columns ' cycle through each row that has seen a change
r.Locked = r.Cells(row_to_check, 1).Value = "Yes" ' set it to protected if the second cell on that row is "Yes"
Next
Me.Protect ' reprotect the sheet
End Sub
enter image description hereI have an Excel workbook that runs a macro and in the end displays everything in a pivot table
I am trying to add a msgbox when my pivot table has an empty cell (at the end of my macro)
I already did the conditional formatting version(color blank cells red) and it works fine, but the client wants a msgbox to alert him.
I found a IsEmpty command that should work but I cant seem to make it look only inside said pivot table.
Here is what I tried:
Sub IsEmpty()
If IsEmpty(ActiveSheet.Range("PivotTables(1)")) = True Then
'Cell A2 is not blank
MsgBox "Cell A2 is empty"
Else
End If
End Sub
I'm sure the way my If statement is written is false. Just cant seem to find the right syntax.
Thanks in advance
Picture added; I want the macro to target pivot's C column. However, you cant know which cell will be empty or how long the list will continue.
And if just make Excel check a broad spectrum(c2:c300), there will always be en empty cell after the pivot table is finished.
There might be a loop you can create but its way over my current skill set.
The pivot table's name is "PivotTable2"
Is there a to search only in the pivot table's column c for empty cells?
Please consider the capabilities of the function below. It will return True or False depending upon the count of items in columns A and C. In column A text, number or function is counted. In column C there must be a number in each cell. If both counts are the same the function returns True. Either count can be further refined if there are exceptions which the current function doesn't correction evaluate.
Function IsComplete() As Boolean
' 025
Dim Rng As Range
With ThisWorkbook.Sheets("PivotTables(1)") ' change to suit
' set a range from A3 to end of column A
Set Rng = .Range(.Cells(3, "A"), .Cells(.Rows.Count, "A").End(xlUp))
End With
With Application.WorksheetFunction
IsComplete = (.CountA(Rng) = .Count(Rng.Offset(0, 2)))
End With
End Function
You can use code to call this function and display a message box for True and another one if the function returns False. The code can be hitched to a button on your sheet, anywhere in your workbook.
Sub CommandButton1_Click()
Dim Txt As String
If IsComplete Then
Txt = "The pivot table was created without mistakes."
Else
Txt = "Some data are missing in the pivot table."
End If
MsgBox Txt, vbInformation, "Action report"
End Sub
You can also call the function as a UDF and display True or False in a cell of any sheet in your workbook. The UDF call would be like =IsComplete(). You might also embed the UDF call in an IF condition and display another text on your worksheet.
=IF(IsComplete(),"All's well","Missing Item")
In fact, you could slightly modify the function to return the difference between one count and the other and display "1 item missing". The possibilities are endless because the function is so versatile.
I've set up a VBA code that sets up a form for the user to fill out information. I've set up another VBA code that runs upon sheet calculation that runs some checks and corrections to any information that is out of line. As soon as the second code runs all sheet calculation stops and I can only edit the first unlocked cell, even when sheet protection is off and I have selected another cell. All typing goes to the first unlocked cell.
This script has worked when triggered by selection change or by running the script manually. I've searched the internet but all I find are list of settings (all of which I have checked).
Private Sub Worksheet_Calculate()
'Transfer
'
If Range("AAA1").Value = "Transfer" And Range("AAB1").Value = "Not Empty" Then
If Range("D3").Value = "0" Or Range("D3").Value = "" Then
Range("AAB1").Value = "Empty"
End If
End If
If Range("AAA1").Value = "Transfer" And Range("AAB1").Value = "Empty" Then
If Range("E3").Value = Empty Or Range("F3").Value = Empty Then
Else
Range("D3").Value = Range("AA3").Value
Range("AAB1").Value = "Not Empty"
End If
End If
If Range("D3").Value > Range("AA3").Value And Range("AAA1").Value = "Transfer" Then
Range("D3").Value = Range("AA3").Value
End If
End Sub
The expected result is for cell D3's value to be automatically set to the max value (calculated in cell AA3 using the value in cell E3) when both cells E3 and F3 have been filled out and cell D3 is either empty or equal to zero. I use cell AAB1 as a "switch" so that the user can enter a custom amount without a hasle. Cell AAA1 is set by the first macro that sets up the form. It all works once. Then I encounter the problem described above.
I followed the advice of Harassed Dad and put Application.EnableEvents = FALSE at the very beginning of the script and = TRUE at the very end. It did the trick. I didn't think that changing values would trigger calculation before the script had finished. Thanks guys.
I have a cell on Sheet1 that contains a drop-down list, let's say N3. The items in the drop down change, depending on the value in J3. At start, both cells are blank. Enter data in J3, and the drop down populates in N3. If I clear the contents of J3, the drop down in N3 is now empty, but the last selected value (if one was selected), still appears as a 'ghost' entry. It's a ghost entry to ME because it is old data, but I do understand the software is doing as designed. If J3 is cleared of contents, how do I get N3 to be cleared of that last selection? I am not VBA trained, but dangerous enough to handle it if that's what's needed to accomplish this. thanks!
You may consider to use the worksheet_change event.Put the below code in sheet1 code module.
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo err_rout
Application.EnableEvents = False
If Not Intersect(Range("J3"), Target) Is Nothing And Target.Value = vbNullString Then
Range("N3").Value = vbNullString
End If
err_rout:
Application.EnableEvents = True
End Sub